2015-11-18 3 views
2

Я пишу код, который требует от меня сохранения коллекции двух типов объектов (например, класса Derived1 и класса Derived2), которые имеют один и тот же базовый класс (например, класс Base). Базовый класс также имеет чистую виртуальную функцию, которая имеет реализацию в обоих этих производных классах.C++ Копирование вектора указателей с полиморфизмом

Я отслеживаю все эти объекты, используя вектор точек для объектов базового класса (т. Е. Вектор < * Base> myCollection). Однако мне часто приходится делать копии этого вектора.

Я попытался создать функцию копирования в базовом классе, чтобы создать другие экземпляры Derived1 или Derived2. Однако я заметил какое-то странное поведение.

Вот пример такого поведения:

#include <iostream> 
#include <vector> 
#include <string> 
using namespace std; 

class A 
{ 
public: 
    int member; 
    string name; 
    A(int x, string str = "Base"): member(x), name(str) {} 
    A* CreateCopy() 
    { 
     A tmp = A(member); // tmp: member = 77, name = "Base" 
     return &tmp;  // &tmp: member = 77, name = "" 
    } 
}; 

class B : public A 
{ 
public: 
    B(int x) : A(x, "Derived Class") {} 
}; 

int main() 
{ 
    A* ptr = &B(77);    // &tmp: member = 77, name = "" 
    B test(77);      // test: member = 77, name = "Derived Class" 
    A* ptr2 = &test;    // *ptr2: member = 77, name = "Derived Class" 
    A* newPtr = ptr->CreateCopy(); // *newPtr: member = 77, name = "" 

    return 0; 
} 

Когда я создаю объект B и присвоить ссылку объекта на той же строке, я теряю правильность элемента имени. Однако, когда я создаю объект, а затем назначаю его ссылку, он работает. К сожалению, я получаю ту же проблему с моим методом CreateCopy().

Что здесь происходит и что является лучшим способом для копирования вектора указателей? Можно ли выполнить копию без использования «нового» оператора? Похоже, утечки памяти чаще возникают при использовании этого оператора.

Большое вам спасибо за ваш совет!

+2

Вы не можете вернуть адрес временного типа (это неопределенное поведение). Я предлагаю вам повысить уровень предупреждения вашего компилятора и обратить внимание на эти предупреждения. Если вы хотите работать с такими указателями, вам нужно выделить память с чем-то вроде 'new'. – Cornstalks

ответ

2

Для A* ptr = &B(77);, B(77) - временный объект, который будет уничтожен, когда выражение закончено, а затем ptr станет болтающимся указателем.

Для

A* CreateCopy() 
{ 
    A tmp = A(member); // tmp: member = 77, name = "Base" 
    return &tmp;  // &tmp: member = 77, name = "" 
} 

tmp является локальной переменной, которая будет разрушена, когда из области видимости функции, это означает, что CreateCopy() возвращает указатель болтался.

Возможно ли выполнить копию без использования «нового» оператора? Похоже, утечки памяти чаще возникают при использовании этого оператора.

Вы можете использовать интеллектуальный указатель, чтобы избежать ручного управления памятью. Например, std::unique_ptr или std::shared_ptr.

+0

Хотя это проблема с кодом, на самом деле он не отвечает на вопрос (лучший способ скопировать) IMO. – ajshort

+1

@ajshort: Он отвечает на один из вопросов («Что здесь происходит»), по крайней мере. Это не может быть 100% полный ответ, который затрагивает все части этого вопроса, но это, вероятно, полезно для OP. – Cornstalks

+1

@ajshort Я добавил, что лучший способ скопировать IMO. – songyuanyao

Смежные вопросы