2015-03-14 3 views
0

Я хотел бы иметь возможность вызвать нетривиальный конструктор объекта, когда я использую метод push_back(). Вместо этого все, что я мог сделать, это передать мелкую копию объекта в вектор. При использовании регулярных массивов c-style конструктор автоматически вызывается при создании массива, но поскольку векторы являются динамическими, объект еще не существует.Инициализировать объект с помощью указателей в векторе C++

Как я могу добавить новый пустой объект к вектору, не имея двух указателей на один и тот же адрес памяти? Нужен ли мне конструктор копирования или перегруженный оператор присваивания?

Вот пример кода, который демонстрирует мою проблему:

struct Object 
{ 
    int *Pointer; 

    Object() 
    { 
     Pointer = new int; 
     *Pointer = 42; 
    } 

    ~Object() 
    { 
     delete Pointer; 
    } 
}; 


int main() 
{ 
    std::vector <Object> *Array; 
    Array = new std::vector <Object>; 

    // Attempt 1 
    Array->push_back(Object()); 

    // Attempt 2 
    { 
     Object LocalInstance; 
     Array->push_back(LocalInstance); 
    } 

    // Error here because the destructor has already been called for 
    // LocalInstance and for Object() 
    delete Array; 

    return 0; 
} 
+2

Не использовать указатели здесь. Это необязательно и делает код менее эффективным и более сложным. –

+0

Это упрощение фактического кода, чтобы облегчить задачу поиска/отладки. Фактический код должен иметь эти указатели. – JubileeTheBear

+0

Даже если вам действительно нужен указатель, вы должны предпочесть интеллектуальные указатели в контейнерах STL, таких как [boost :: shared_ptr] (http://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/shared_ptr.htm) или [std :: shared_ptr] (http://en.cppreference.com/w/cpp/memory/shared_ptr). – dbank

ответ

1

@KonradRudolph правильно - нет никаких оснований для Array быть указатель здесь, и это только запутывает код.

Причина ваш код падает потому, что LocationInstance передается push_back но ваш Object не имеет надлежащего конструктор копирования, так что только неполную копию Pointer элемента копируется. Когда LocalInstance выходит из области видимости, этот объект удаляет свой Pointer, но копия в контейнере имеет то же самое Pointer, что приводит к удалению освобожденной памяти при очистке контейнера.

Пожалуйста, проверьте Rule-of-Five (было Правило-трое до C++ 11).

Что касается объектов строительства, когда вы добавляете их в контейнер, используете ли вы C++ 11? Если да, вы можете emplace_back и построить объект в контейнере по мере его добавления - это то, что вы хотите сделать?

Этот тривиальный пример только дает мне предупреждение с лязгом:

struct A 
{ 
    A(int a) : member_m(a) 
    {} 

    int &member_m; 
}; 
int main() { 
    A a(1); 
} 

дает мне:

~/ClionProjects/so_reference_to_temporary $ clang++ -o test main.cpp 
main.cpp:8:25: warning: binding reference member 'member_m' to stack allocated 
     parameter 'a' [-Wdangling-field] 
    A(int a) : member_m(a) 
         ^
main.cpp:13:10: note: reference member declared here 
    int &member_m; 
     ^
1 warning generated. 
+0

Я использовал указатель для массива объектов, потому что без него ошибка не получается (по крайней мере, не для меня). Что произойдет, так как память будет освобождена, но указательный элемент объекта в aray укажет на неверный адрес памяти. Я динамически выделял массив, чтобы заставить компилятор генерировать ошибку, когда деструктор вызывался дважды. – JubileeTheBear

+1

Это просто «удача» - удаление освобожденной памяти - это неопределенное поведение. Как и во многих ошибках памяти, иногда, когда вам повезет, это сбой. Иногда он просто работает нормально, пока это не произойдет. Такие инструменты, как valgrind, очень полезны для проверки кода для таких проблем. – sfjac

+0

Вы были правы, мне нужен был только конструктор копирования. По какой-то причине это не сработало в первый раз, но теперь это происходит. – JubileeTheBear