我在C ++中有一个奇怪的'析构函数'行为
以下是我调用的代码:
_log->OnCommit();
delete _log;
问题是当我调用“delete _log;”时它崩溃是因为变量'Entries'无效!!!!
你知道为什么吗?
以下是我的课程代码:
struct TransactionLogEntry {
DependencyObject* Object;
bool IsAttached;
bool IsDeleted;
bool IsUpdated;
};
class TransactionLog
{
public:
TransactionLog();
~TransactionLog();
void OnCommit();
map<DependencyObject*, TransactionLogEntry*> Entries;
};
void TransactionLog::OnCommit()
{
map<DependencyObject*, TransactionLogEntry*>::iterator it;
for(it = Entries.begin(); it != Entries.end(); it++)
{
TransactionLogEntry* entry = (TransactionLogEntry*)(*it).second;
if (entry->IsDeleted)
delete entry->Object;
delete entry;
}
Entries.clear();
}
TransactionLog::~TransactionLog()
{
map<DependencyObject*, TransactionLogEntry*>::iterator it;
for(it = Entries.begin(); it != Entries.end(); it++)
{
TransactionLogEntry* entry = (TransactionLogEntry*)(*it).second;
delete entry;
}
Entries.clear();
}
答案 0 :(得分:3)
如果没有完整的代码,很难看到,但我可以注意到你违反了三巨头的规则(你有一个析构函数,但没有复制构造函数或赋值运算符),这意味着要找麻烦。
我猜测你是复制构建日志或其他类似问题,一旦你进入UB模式,就会发生任何事情,包括在应该没问题的地方引发错误。
答案 1 :(得分:1)
As said,您错过了TransactionLog的复制ctor和赋值运算符。这是问题,简化:
struct A {
int *p;
A() : p (new int()) {}
~A() { delete p; }
}
这适当地分配和销毁一个对象,对吧?不完全:
void example() {
A a;
A b = a; // Missing copy ctor; could also happen when passing/returning by value.
b = a; // Same result through missing assignment operator.
assert(a.p == b.p); // Here is the problem!
// When b is destroyed, it deletes the pointer.
// When a is destroyed, it attempts to delete the deallocated pointer,
// leading to undefined behavior.
}
以下是与您的代码更紧密地编写相同的问题:
struct A {
map<string, int*> m;
A() {
m["abc"] = new int();
}
~A() {
for (map<string, int*>::iterator x = m.begin(); x != m.end(); ++x) {
delete x->second;
}
}
void on_commit() {
for (map<string, int*>::iterator x = m.begin(); x != m.end(); ++x) {
delete x->second;
}
m.clear();
}
}
解决方案是为您的类声明一个复制ctor和赋值运算符。即使你的课程是'不可复制的'#34;,你仍然应该声明它们,但要将它们设为私有且不要定义它们:
struct A {
int *p;
A() : p (new int()) {}
~A() { delete p; }
private:
A(A const&);
A& operator=(A const&);
}
当它们是私有的时,任何使用(在不可访问的上下文中)都将是编译器错误。
答案 2 :(得分:1)
您是否在Entries
地图中存储了裸指针?如果是这样,您应该使用boost::shared_ptr
(或tr1::shared_ptr
,如果有的话)进行调查。这极大地简化了存储管理(例如,您可以删除for
中的TransactionLog::OnCommit()
循环,只需拨打Entries.clear()
。
答案 3 :(得分:0)
查看OnCommit功能中的内容:
...
if (entry->IsDeleted)
delete entry->Object;
delete entry;
...
看起来你检查是否有东西被删除了。如果是这样,您删除其中的内容并始终再次删除该对象。看起来你在问问题。
答案 4 :(得分:0)
如前所述,尽量避免使用裸c / c ++指针指向对象,而是使用某种智能ptr(例如boost :: shared_ptr)或auto_ptr来简单保存/释放资源(但不是stl容器由于auto_ptr特定)
关于此崩溃:没有什么可以阻止您使用不同的键但相同的值填充地图对象。所以有可能删除对象两次或更多次,这肯定会导致崩溃(如果它等于0,你可以删除指针两次或更多次)。所以写下:
删除ptr; ptr = 0;
而不只是删除指针