В C ++ возможно ли получить доступ к статической переменной в конструкторе? - PullRequest
3 голосов
/ 03 декабря 2011

Я пытаюсь:

class MyClass {
public:
    MyClass();

    int myID;
    static int currentID;
};

MyClass::MyClass() {
    myID = currentID;
    ++currentID;
}

Я пытаюсь назначить уникальный идентификатор всем экземплярам этого класса.

Редактировать:

Это не 'я не работаюЯ получаю два из них в xcode:

Неопределенные символы: "GameObject :: currentID", на которые ссылаются из: __ZN10GameObject9currentIDE $ non_lazy_ptr в GameObject.o (может быть, вы имели в виду: __ZN10GameObject9currentIDE $ non_lazy_ptr (l): not_lazy_ptr)найдено collect2: ld вернул 1 статус выхода

Ответы [ 7 ]

5 голосов
/ 03 декабря 2011

У меня работает:

#include <iostream>

class My
{
    public:
    My() : id(++currentId) {}

    int id;
    static int currentId;
};

int My::currentId = 0;

std::ostream & operator<<(std::ostream & os, My & m)
{
    return os << m.id;
}

int main()
{
    My a;
    My b;
    My c;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
}

Вывод:

> ./x
1
2
3
3 голосов
/ 03 декабря 2011

Помимо других случаев, он работает в следующих случаях:

MyClass a[10];
MyClass* b = new MyClass[10];

Будьте осторожны, если вы используете контейнеры STL для хранения MyClass объектов. Возможно, он не ведет себя так, как вы ожидали, и проблему трудно найти. См. Следующий пример:

int MyClass::currentID = 0;
...
std::vector<MyClass> c(10);
MyClass a;

В этом случае результат будет следующим:

c[0].myID = 0;
c[1].myID = 0;
....
c[9].myID = 0
=============
   a.myID = 1. 

Конструктор по умолчанию выполняется только ОДИН раз. Причина в том, что конструктор std :: vector будет использовать одно и то же значение для инициализации всех элементов вектора. В моей системе конструктор std :: vector имеет следующий вид:

  explicit
  vector(size_type __n, const value_type& __value = value_type(),
     const allocator_type& __a = allocator_type())
  : _Base(__n, __a)
  { _M_fill_initialize(__n, __value); }   

_M_fill_initialize инициализирует выделенную память, используя __value (что происходит из конструктора по умолчанию value_type()) __n раз.

Приведенный выше код в конечном итоге вызовет uninitialized_fill_n, что делает следующее:

for (; __n > 0; --__n, ++__cur)
    std::_Construct(&*__cur, __x);

Вот std::_Contruct:

template<typename _T1, typename _T2>
inline void
_Construct(_T1* __p, const _T2& __value)
{
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 402. wrong new expression in [some_]allocator::construct
  ::new(static_cast<void*>(__p)) _T1(__value);
}

Здесь вы видите, что он наконец вызывает глобальный оператор new, чтобы инициализировать каждый элемент в векторе, используя то же значение .

Вывод таков: использование статического элемента в качестве исходного элемента данных будет работать в большинстве случаев, но может не сработать, если вы планируете использовать его в контейнерах STL, и эту проблему трудно найти. Я только попробовал std::vector, вполне возможно, что проблема существует при использовании других типов stl-контейнеров с MyClass объектами.

1 голос
/ 03 декабря 2011

Причина, по которой вы получаете ошибку, не в том, что вы получаете доступ к статическому из конструктора, что является допустимым, а потому, что вы не определяете его.

class My
{
    public:
    My() : id(++currentId) {}

    int id;
    static int currentId;
};

//place the definition in the implementation file
int My::currentId = 0;
0 голосов
/ 04 января 2019

Необходимо убедиться, что вы определяете и инициализируете статический член класса вне класса. Это работает для меня:

#include <iostream>
class MyClass {
private:
    int myID;
    static int currentID;
public:
   //default constructor
    MyClass()
        : myID(currentID) 
        {
            ++currentID;
        }

    void printId() { std::cout << "Object Id :" << myID << std::endl; } /*Prints the unique ID assigned to each object.*/
};

// define the static class member here:
int MyClass::currentID = 1;

int main()
{
    MyClass m1, m2, m3;
    m1.printId();
    m2.printId();
    m3.printId();
}

Выход:

Идентификатор объекта: 1

Идентификатор объекта: 2

Идентификатор объекта: 3

0 голосов
/ 03 декабря 2011
int MyClass::currentID=0;  

Если это не сделано, вам нужно сделать это в файле CPP

0 голосов
/ 03 декабря 2011

Да, все в порядке. Но код, который вы написали, не является поточно-ориентированным: два класса могут быть созданы одновременно в разных потоках. Второй экземпляр может получить то же значение currentID, прежде чем первый экземпляр успеет увеличить статическую переменную.

Это может или не может быть проблемой для вас.

Если вам нужна безопасность потоков, этот вопрос должен помочь.

0 голосов
/ 03 декабря 2011

да, это нормально, если у вас нет статических экземпляров MyClass.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...