Подтвердить что ты не робот

С++ std:: tuple порядок уничтожения

Есть ли правило, в котором указано, в каком порядке уничтожены члены std:: tuple?

Например, если Function1 возвращает std::tuple<std::unique_ptr<ClassA>, std::unique_ptr<ClassB>> в Function2, то могу ли я быть уверенным, что (когда область Function2 оставлена), экземпляр ClassB, на который ссылается второй член, уничтожается перед экземпляром ClassA, на который ссылается первый член?

std::tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > Function1()
{
    std::tuple< std::unique_ptr< ClassA >, std::unique_ptr< ClassB > > garbage;
    get<0>(garbage).reset( /* ... */ );
    get<1>(garbage).reset( /* ... */ );
    return garbage;
}

void Function2()
{
    auto to_be_destroyed = Function1();
    // ... do something else

    // to_be_destroyed leaves scope
    // Is the instance of ClassB destroyed before the instance of ClassA?
}
4b9b3361

Ответ 1

В стандарте не указывается порядок разрушения для std::tuple. Тот факт, что в §20.4.1/p1 указано, что:

Создание экземпляра кортежа с двумя аргументами аналогично создание пары с теми же двумя аргументами.

Подобный здесь не интерпретируется как идентичный, и поэтому он не подразумевает, что std::tuple должен иметь порядок обратного уничтожения своих аргументов.

Учитывая рекурсивный характер std::tuple, наиболее вероятным является то, что порядок разрушения упорядочен по порядку его аргументов.

Я также основываю свои предположения на отчете об ошибке для GCC BUG 66699, где в обсуждении мои предположения выше оправданы.

Тем не менее, порядок уничтожения для std::tuple не указан.

Ответ 2

Я предлагаю урок жизни, который я узнал, а не прямой ответ, в ответ на ваш вопрос:

Если вы можете сформулировать для нескольких альтернатив разумный аргумент в пользу того, почему эта альтернатива должна соответствовать той, которая предусмотрена стандартом, - тогда вы не должны предполагать, что любой из них имеет мандат (даже если один из они случаются).

В контексте кортежей - пожалуйста, будьте добры к людям, поддерживающим ваш код, и не позволяйте порядку уничтожения элементов кортежа потенциально испортить уничтожение других элементов. Это просто зло... представьте себе несчастного программиста, которому нужно будет отладить эту вещь. Фактически, эта бедная душа может быть собой через несколько лет, когда вы уже забыли про свой хитрый трюк из-за-в-день.

Если вы абсолютно должны полагаться на порядок уничтожения, возможно, вам следует просто использовать правильный класс с элементами кортежа в качестве своих членов данных (для которых вы могли бы написать деструктор, давая понять, что должно произойти в каком порядке) или какой-либо другой механизм, облегчающий более явный контроль над уничтожением.

Ответ 3

С Clang 3.4 я получаю тот же порядок уничтожения как для std::pair, так и для 2 элемента std::tuple, а с g++ 5.3 я получаю противоположный порядок, который может быть в основном обусловлен рекурсивной реализацией std::tuple в libstd ++.

Итак, это в основном сводится к тому, что я сказал в комментарии, это реализация определена.

Из отчета BUG:

Комментарий Мартина Себора

Поскольку макет элементов std:: pair полностью задан, порядок их инициализации и уничтожения. Выход теста случай отражает этот порядок.

Порядок инициализации (и уничтожения) субобъектов std: stuple менее четко указано. По крайней мере, это не сразу видно из мое чтение спецификации, если требуется какой-либо конкретный порядок.

Причина, по которой вывод std:: tuple с libstdС++ является обратным std:: pair - это потому, что реализация, которая опирается на рекурсивную наследование, сохранение и построение элементов кортежа в обратном порядке порядок: то есть базовый класс, который хранит последний элемент, сохраняется и построены сначала, за которым следует каждый производный класс (каждый из которых хранит последний - N-й элемент).

Цитата из стандарта [раздел 20.4.1], которую репортер ошибок цитирует

1 В этом подпункте описывается библиотека кортежей, которая предоставляет кортеж введите в качестве кортежа шаблона класса, который может быть создан с помощью любого количество аргументов. Каждый аргумент шаблона указывает тип элемент в кортеже. Следовательно, кортежи являются гетерогенными, коллекции фиксированных размеров. Создание кортежа с двумя аргументы аналогичны экземпляру пары с теми же двумя Аргументы. См. 20.3.

Аргумент против этого в связанной ошибке:

Будучи описанным как похоже, не означает, что они одинаковы в каждом подробно. std:: pair и std:: tuple - это разные классы с разными требования к каждому. Если вы считаете, что они должны вести себя тождественно в этом отношении (т.е. имеют свои подобъекты, определенные в в том же порядке), вы должны указать на конкретную формулировку, которая гарантирует это.