"Переместить или бросить" с помощью троичного оператора - программирование

"Переместить или бросить" с помощью троичного оператора

Начиная с C++ 11 я использую троичный оператор для перемещения или броска в зависимости от некоторых условий, но с последним GCC (9.1 и транк) больше не работает.

Я уменьшил проблему до этого примера (постоянная ссылка Wandbox):

#include <iostream>
#include <memory>

int main() 
{
    auto p = std::make_unique<int>();
    std::cout << "p.get(): " << p.get() << std::endl;

    {
        std::cout << "Move p into q" << std::endl;
        auto q = p ? std::move(p) : throw std::invalid_argument{"null ptr"};

        std::cout << "q.get(): " << q.get() << std::endl;
    }

    std::cout << "p.get(): " << p.get() << std::endl;
    return 0;
}

Он работает с GCC 8.3 и старше, а также с каждой версией Clang; и p перемещается:

p.get(): 0xde5c20
Move p into q
q.get(): 0xde5c20
p.get(): 0

Но теперь с GCC 9.1 и позже это не работает:

p.get(): 0x1d89150
Move p into q
q.get(): 0x1d89150
p.get(): 0x1d89150

И тогда программа вылетает из-за двойного освобождения.

Это ошибка в GCC 9.1/trunk? Или последний GCC - единственный, кто делает правильные вещи, и это недействительно C++?

4b9b3361

Ответ 1

Это должно быть ошибкой.

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

q.get() == p.get() действительно показывает, что внутренние q.get() == p.get() сломались, поскольку это не должно быть возможным.

Я согласен с cpplearner, что это ошибка 90393 (и все ее ошибки), которая, как сообщается, была введена в GCC 9.1.