c++ - 析构函数调用时访问冲突读取位置 0xfeeefe2

标签 c++ exception access-violation pimpl-idiom

这篇文章有点大,所以提前抱歉。不管怎样,我在 Debug模式(Visual Studio 2010)下运行程序时遇到异常,我不太明白为什么会发生:

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

我对 C++ 很陌生,我正在尝试实现一个类似 pimpl 的模式类结构,如下所示:

声明.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;
}

现在,当代码转义主 block 时,将调用 B 的析构函数,从而删除实现,而实现又会调用它所持有的实现实例的析构函数,依此类推,直到保存在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++ 并且我已经投入了一些时间试图弄清楚为什么这是一个问题,所以我真的会喜欢了解问题。

最佳答案

我认为当你执行member = a;时,你复制了A中的instance指针,换句话说,member和a指向同一个Implementation。当 A 被删除时,实例 也会被删除。而成员仍然尝试访问实例。

关于c++ - 析构函数调用时访问冲突读取位置 0xfeeefe2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18759731/

相关文章:

c++ - 如何使用 C 语言将整数值转换为相应的十六进制并将其存储在单字节变量中

c++ - 在 C++ 的函数调用中完成强制转换是否真的有效?

delphi - 访问 Intraweb 中的 UserSession 时的访问冲突

c - 第一次机会异常 : KernelBase. dll

c++ - 指针未指向 NULL 时发生访问冲突

c++ - mingw32:所有编译的可执行文件挂起

c++ - 通过 BGL 使用 Min-Cut 的图像分割示例?

java - Java 中的 MATLAB 函数导致运行时错误 (EXCEPTION_ACCESS_VIOLATION)

java - 遍历列表,同时从列表中删除

android - 在 Android 上使用 Web 服务时出现异常错误