【发布时间】:2012-06-20 13:27:42
【问题描述】:
我知道向量元素的破坏顺序不是由 C++ 标准定义的(参见Order of destruction of elements of an std::vector),我看到我检查的所有编译器都从头到尾进行了这种破坏——这让我很惊讶,因为动态和静态数组确实如此它以相反的顺序,而这种相反的顺序在 C++ 世界中很常见。
严格地说:我知道“容器成员......可以使用例如插入和擦除成员函数以任何顺序构造和销毁”并且我不投票支持“容器在这些更改上保留某种日志”。我只会投票支持将当前的向量析构函数实现从前向破坏更改为元素的后向破坏——仅此而已。并且可能将此规则添加到 C++ 标准中。
为什么?这样从数组转换为向量会更安全。
真实世界的例子: 我们都知道互斥锁的锁定和解锁顺序非常重要。并确保解锁发生 - 使用 ScopeGuard 模式。那么销毁顺序很重要。考虑这个例子。那里 - 从数组切换到向量会导致死锁 - 只是因为它们的破坏顺序不同:
class mutex {
public:
void lock() { cout << (void*)this << "->lock()\n"; }
void unlock() { cout << (void*)this << "->unlock()\n"; }
};
class lock {
lock(const mutex&);
public:
lock(mutex& m) : m_(&m) { m_->lock(); }
lock(lock&& o) { m_ = o.m_; o.m_ = 0; }
lock& operator = (lock&& o) {
if (&o != this) {
m_ = o.m_; o.m_ = 0;
}
return *this;
}
~lock() { if (m_) m_->unlock(); }
private:
mutex* m_;
};
mutex m1, m2, m3, m4, m5, m6;
void f1() {
cout << "f1() begin!\n";
lock ll[] = { m1, m2, m3, m4, m5 };
cout <<; "f1() end!\n";
}
void f2() {
cout << "f2() begin!\n";
vector<lock> ll;
ll.reserve(6); // note memory is reserved - no re-assigned expected!!
ll.push_back(m1);
ll.push_back(m2);
ll.push_back(m3);
ll.push_back(m4);
ll.push_back(m5);
cout << "f2() end!\n";
}
int main() {
f1();
f2();
}
OUTPUT - 查看销毁顺序从 f1() 到 f2()
f1() begin!
0x804a854->lock()
0x804a855->lock()
0x804a856->lock()
0x804a857->lock()
0x804a858->lock()
f1() end!
0x804a858->unlock()
0x804a857->unlock()
0x804a856->unlock()
0x804a855->unlock()
0x804a854->unlock()
f2() begin!
0x804a854->lock()
0x804a855->lock()
0x804a856->lock()
0x804a857->lock()
0x804a858->lock()
f2() end!
0x804a854->unlock()
0x804a855->unlock()
0x804a856->unlock()
0x804a857->unlock()
0x804a858->unlock()
【问题讨论】:
-
恕我直言,如果软件设计良好,销毁顺序应该无关紧要。当调用析构函数时,这意味着对象不再使用或不再需要。在销毁对象之前,您应该确保对象处于一致状态(在这种情况下不再使用)。
-
我们也都知道,当执行顺序如此重要时,将它们放在任何容器中并让生成的代码破坏并不是一个好主意。 // 讽刺通知:我对“我们都知道”的说法有点怀疑
-
可能你没有阅读就回答了。 n ScopeGuard (stackoverflow.com/questions/48647/…) 我在这里使用,销毁顺序很重要。这就是我使用这个例子的原因。
-
@user1463922:我知道 RAII 和范围守卫。我只是说,当订单很重要时,你应该自己销毁这些条目,从容器中弹出它们。
-
具体来说“现实世界的例子”:按不同的顺序解锁怎么可能造成死锁?解锁(和 try_lock)永远不会阻塞,因此不可能参与死锁,死锁定义为阻塞循环。我错过了什么吗?
标签: c++ vector standards destruction