这篇文章会有点大,所以提前抱歉。无论如何,我在调试模式(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的析构函数,然后删除实现,后者又调用它所持有的实例实例的析构函数,依此类推,直到向量中包含的向量束ofStructs的析构函数为止。调用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
,则代码将运行。此外,如果我没有模式实现它,它似乎运行良好。 E.g:
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 ++而且我已经花了一些时间试图弄清楚为什么这是一个问题,我会真的喜欢理解这个问题。
答案 0 :(得分:3)
我认为您在执行instance
时复制A中的member = a;
指针。换句话说,成员和指向同一Implementation
的点。当A被删除时,instance
会被删除。成员仍然尝试访问实例。
答案 1 :(得分:2)
当您执行member = a;
时,您正在执行对象的位到位副本,类型为A
。此时member.instance
等于a.instance
,即它是指向创建A::A()
时在a
中分配的内存的指针。
当B::Implementation::doWork()
终止时,会调用a
的析构函数,然后删除a.instance
;此操作使member.instance
成为悬空指针。