2013-09-12 5 views
2

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

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, который, в свою очередь, удаляет реализацию, которая, в свою очередь, вызывает деструктор для экземпляра реализации, который она хранит, и так далее, пока деструктор для векторного bunchOfStructs не будет сохранен в экземпляре А называется. И здесь он терпит неудачу.

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

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++ и Я уже потратил некоторое время на то, чтобы понять, почему это проблема, в первую очередь мне очень хотелось бы понять проблему.

+0

Цель использования pimpl заключается в том, чтобы скрыть внутренние детали класса от клиентов, которые включают заголовок. Но похоже, что вы также вставляете детали реализации в заголовок - если вы собираетесь это сделать, зачем вообще беспокоиться о pimpl? – greatwolf

+0

Немедленно обратите внимание, что ошибка находится в 'msvcp100d.dll', что означает, что std-объект, вероятно, будет очищен дважды.Образец байта, который вы видите, заполняется для RT, когда он уже освободил базовую память. Таким образом, что-то, что * держит * объект std, вероятно, будет дважды удалено или доступно после удаления. – WhozCraig

+2

Вы нарушаете правило трех, что, вероятно, и является причиной, как указывает Enigma. http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three –

ответ

2

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

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

3

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

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

  • Нет связанных вопросов^_^