2010-04-27 3 views
5

Я столкнулся с следующей ошибкой.связанный с памятью вопрос о распределении памяти

  • У меня есть класс Foo. Экземпляры этого класса хранятся в std :: vector vec от class B.
  • в классе Foo, я создаю экземпляр класса A путем выделения памяти с помощью new и удаления этого объекта в ~Foo().

код компилируется, но я получаю сбой во время выполнения. Если я отключу delete my_a от десстрефатора класса Foo. Код работает нормально (но будет утечка памяти).

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

спасибо!

class A{ 
     public: 
      A(int val); 
      ~A(){}; 
      int val_a; 

}; 

A::A(int val){ 
     val_a = val; 
     }; 

class Foo {  
     public: 
      Foo(); 
      ~Foo(); 
      void createA(); 
      A* my_a; 
}; 

Foo::Foo(){ 
    createA(); 
}; 

void Foo::createA(){ 
    my_a = new A(20); 
}; 

Foo::~Foo(){ 
    delete my_a; 

}; 



class B { 
     public: 
      vector<Foo> vec;    
      void createFoo();    
      B(){}; 
      ~B(){}; 
}; 


void B::createFoo(){ 
    vec.push_back(Foo()); 
}; 


int main(){ 
    B b; 

    int i =0; 
    for (i = 0; i < 5; i ++){ 
     std::cout<<"\n creating Foo"; 
     b.createFoo(); 
     std::cout<<"\n Foo created"; 
     } 
    std::cout<<"\nDone with Foo creation"; 

    std::cout << "\nPress RETURN to continue..."; 
    std::cin.get(); 

    return 0; 
} 

ответ

7

Вам необходимо реализовать конструктор копирования и оператор присваивания для Foo. Всякий раз, когда вы обнаружите, что вам нужен деструктор, вам наверняка тоже нужны эти два. Они используются во многих местах, особенно для размещения объектов в контейнерах стандартной библиотеки.

Конструктор копирования должен выглядеть следующим образом:

Foo :: Foo(const Foo & f) : my_a(new A(* f.my_a)) { 
} 

и оператор присваивания:

Foo & Foo :: operator=(const Foo & f) { 
    delete my_a; 
    my_a = new A(* f.my_a); 
    return * this; 
} 

Или еще лучше, не создают Экземпляр в классе Foo динамически:

class Foo {  
     public: 
      Foo(); 
      ~Foo(); 
      void createA(); 
      A my_a; 
}; 

Foo::Foo() : my_a(20) { 
}; 
+0

Спасибо Нейл. Как мне создать экземпляр класса A? Было бы очень полезно оценить фрагмент кода. Кроме того, как бы копировать конструктор и код оператора присваивания. Большое спасибо – memC

+1

Neil у вас есть опечатка ... new A (f.my_a); -> новый A (* f.my_a); – TimW

+0

привет Нейл, большое спасибо за фрагмент кода. На самом деле, я хочу передать 'int val' для' my_a', помещая экземпляр Foo в вектор. как это сделать? -> Мне нужно что-то вроде этого: (конечно, это не работает) 'vec.push_back (Foo(): my_a (40)' – memC

2

Объект Foo копируется и при уничтожении каждой копии delete вызывается на s ame значение указателя my_a. Внедрите оператор копирования и присваивания для Foo или используйте интеллектуальный указатель.

Foo(const Foo& s) : my_a(s.my_a ? new A(*s.my_a) : 0) { 
} 

Foo& operator= (const Foo& s) { 
    Foo temp(s); 
    temp.swap (*this); 
    return *this; 
} 

void swap (Foo &s) { 
    std::swap (my_a, s.my_a); 
}; 
+0

+1 для умного указателя – hamishmcn

+0

спасибо Тиму за ответ. – memC

3

Если вы не указали конструктор копирования, компилятор сделает его для вас. Созданный компилятором экземпляр копии выглядит так:

Foo::Foo(const Foo& copy) 
    : my_a(copy.my_a) 
{} 

Woops! Вы копируете только указатель, но не указательную память. И ваш временный Foo() в createFoo(), и тот, который скопирован в вектор, указывает на ту же память, поэтому память удаляется дважды, что приводит к сбою вашей программы во втором удалении.

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

Foo::Foo(const Foo& copy) 
    : my_a(new A(*copy.my_a)) 
{} 

Примечание это происходит сбой, если copy имеет NULL my_a элемент, и он также вызывает конструктор копирования на A, которые вы не указали или. Поэтому вы захотите внести некоторые дополнительные изменения. Вам также понадобится перегрузка operator=.

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