我知道向量元素的破坏顺序不是由 C++ 标准定义的(请参见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();
}
输出 - 查看从 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()