Доступ к месту чтения нарушения 0xfeeefe2 при вызове деструктора

Этот пост будет немного большим, поэтому заранее извините. Во всяком случае, я получаю исключение при запуске моей программы в режиме отладки (Visual Studio 2010), что я не могу понять, почему это происходит:

Unhandled exception at 0x5524ad4a (msvcp100d.dll) in CppTest1.exe: 0xC0000005: Access violation reading location 0xfeeefef2.

Я довольно новичок в C++, и я пытаюсь реализовать структуру класса шаблонов, подобную pimpl, например:

declaration.h

#include <vector>
class A
{
public:
  struct aStruct
  {
    std::string aString;
    std::vector<std::string> moreStrings;
  };
  A();
  ~A();
  void addSomething(aStruct thing);
private:
  class Implementation;
  Implementation* instance;
};

class B
{
public:  
  B();
  ~B();
  void doWork();
private:
  class Implementation;
  Implementation* instance;
};

class A::Implementation
{
public:
  Implementation();
  ~Implementation();
  void addSomething(aStruct thing);
private:
  std::vector<A::aStruct> bunchOfStructs;
};

class B::Implementation
{
public:
  Implementation();
  ~Implementation();
  void doWork();
private:
  A member;
};

main.cpp

#include "declaration.h"
A::A() : instance(new Implementation) {}
A::~A() { delete instance; }
void A::addSomething(aStruct thing) { instance->addSomething(thing);}

A::Implementation::Implementation() {}
A::Implementation::~Implementation() {}
void A::Implementation::addSomething(aStruct thing) { bunchOfStructs.push_back(thing);}

B::B() : instance(new Implementation) {}
B::~B() {delete instance;}
B::Implementation::Implementation() { doWork();}
B::Implementation::~Implementation() {}
void B::Implementation::doWork()
{
  A a; 
  member = a;
}

int main( int argc, char* argv[] ) 
{
  B b;  
  return 0;
}

Теперь, когда код выходит за пределы основного блока, вызывается деструктор для B, который, в свою очередь, удаляет реализацию, которая, в свою очередь, вызывает деструктор для экземпляра реализации, который он содержит, и так далее, пока деструктор для вектора bundOfStructs не будет храниться в экземпляре A называется. И вот где это не удается.

Стек вызовов выглядит так:

msvcp100d.dll!std::_Container_base12::_Orphan_all()  Line 201 + 0x12 bytes  C++
CppTest1.exe!std::vector<A::aStruct,std::allocator<A::aStruct> >::_Tidy()  Line 1304 + 0xb bytes    C++
CppTest1.exe!std::vector<A::aStruct,std::allocator<A::aStruct> >::~vector<A::aStruct,std::allocator<A::aStruct> >()  Line 706   C++
CppTest1.exe!A::Implementation::~Implementation()  Line 8 + 0x2b bytes  C++
CppTest1.exe!A::Implementation::`scalar deleting destructor'()  + 0x2b bytes    C++
CppTest1.exe!A::~A()  Line 4 + 0x50 bytes   C++
CppTest1.exe!B::Implementation::~Implementation()  Line 14 + 0x2b bytes C++
CppTest1.exe!B::Implementation::`scalar deleting destructor'()  + 0x2b bytes    C++
CppTest1.exe!B::~B()  Line 12 + 0x50 bytes  C++
CppTest1.exe!main(int argc, char * * argv)  Line 24 + 0x12 bytes    C++

Насколько я понимаю, 0xfeeefeee - это шаблон заполнения, используемый в Visual Studio во время отладки. А сообщение об исключении указывает, что я пытаюсь получить доступ к тому, что уже было удалено? Но я не совсем понимаю, почему это происходит. Что-то разрушается, прежде чем я думаю, что это так. Если бы не было назначения member = a код будет работать. Кроме того, если бы я реализовал это без шаблона, казалось бы, все работает нормально. Например:

thisworks.h

#include <vector>
class C
{
public:
  struct aStruct
  {
    std::string aString;
    std::vector<std::string> moreStrings;
  };
  C();
  ~C();
  void addSomething(aStruct thing);
private:
  std::vector<C::aStruct> bunchOfStructs;
};
class D
{
public:
  D();
  ~D();
  void doWork();
private:
  C member;
};

main.cpp

#include "thisworks.h"
C::C() {}
C::~C() {}
void C::addSomething(aStruct thing) { bunchOfStructs.push_back(thing); }

D::D() { doWork(); }
D::~D() {}
void D::doWork()
{
  C c;
  member = c;
}
int main( int argc, char* argv[] ) 
{
  D d;
  return 0;
}

Теперь я понимаю, что, возможно, есть лучшие способы сделать это, однако, поскольку я все еще пытаюсь изучать C++, и я уже потратил некоторое время, пытаясь выяснить, почему это проблема, в первую очередь, которую я действительно хотел бы понять эта проблема.

2 ответа

Решение

Когда вы выполняете member = a; вы выполняете побитовую копию объекта, который имеет тип A, С этой точки зрения member.instance равно a.instanceэто указатель на память, выделенную в A::A() при создании a,

когда B::Implementation::doWork() заканчивается, деструктор для a называется, который в свою очередь удаляет a.instance; эта операция делает member.instance свисающий указатель.

Я думаю, что вы копируете instance указатель в пределах А, когда вы выполняете member = a; Другими словами, член и точка к тому же Implementation, Когда А удаляется instance удаляется. Пока участник все еще пытается получить доступ к экземпляру.

Другие вопросы по тегам