Было бы разумно определить порядок уничтожения элементов вектора?

Я знаю что порядок уничтожения элементов вектора не определен стандартом 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 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()

11
задан Community 23 May 2017 в 12:06
поделиться