会是合理的定义向量元素的破坏命令?(Would it be reasonable to define

2019-09-18 05:32发布

我知道,向量元素破坏为了不被C ++标准定义(见一个std ::向量的元素销毁顺序 ),我看到了,我检查了所有的编译器做到这一点的破坏,从开始到结束-这是相当令人惊讶的我,因为动态和静态数组做以相反的顺序,这相反的顺序是经常在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()

Answer 1:

我认为这是C ++编译器给作家的灵活性,写最高效的集装箱为他们的架构另一种情况。 在一个特定的顺序需要销毁的可能会伤害在类似的情况下0.001%的方便(我其实从来没有见过另一个例子,其中的默认顺序是不适合的)性能。 因为在这种情况下, vector是我指的是硬件的利用前瞻智能高速缓存,而不是向后迭代和反复可能缺少缓存的能力连续数据。

如果需要为您的容器实例破坏的特定顺序,语言要求你自己实现以避免潜在的惩罚的标准功能,其他客户端。



Answer 2:

FWIW, libc的++输出:

f1() begin!
0x1063e1168->lock()
0x1063e1169->lock()
0x1063e116a->lock()
0x1063e116b->lock()
0x1063e116c->lock()
f1() end!
0x1063e116c->unlock()
0x1063e116b->unlock()
0x1063e116a->unlock()
0x1063e1169->unlock()
0x1063e1168->unlock()
f2() begin!
0x1063e1168->lock()
0x1063e1169->lock()
0x1063e116a->lock()
0x1063e116b->lock()
0x1063e116c->lock()
f2() end!
0x1063e116c->unlock()
0x1063e116b->unlock()
0x1063e116a->unlock()
0x1063e1169->unlock()
0x1063e1168->unlock()

这是故意这样实现。 定义的按键功能这里是:

template <class _Tp, class _Allocator>
_LIBCPP_INLINE_VISIBILITY inline
void
__vector_base<_Tp, _Allocator>::__destruct_at_end(const_pointer __new_last, false_type) _NOEXCEPT
{
    while (__new_last != __end_)
        __alloc_traits::destroy(__alloc(), const_cast<pointer>(--__end_));
}

每当这个私有实现细节被称为size()需要收缩。

我还没有收到有关此可见的实现细节的任何反馈,无论是正面还是负面的。



文章来源: Would it be reasonable to define destruction order of vector elements?