Безопасно ли вызывать метод для интеллектуального указателя, который перемещен из аргументов? - PullRequest
3 голосов
/ 16 марта 2020

Этот код безопасен? Меняется ли ответ, если метод принимает значение по значению или значение r? Изменится ли он для unique_ptr?

struct foo
{
    void bar(std::shared_ptr<foo> p) // or std::shared_ptr<foo>&&
    {
        // the object will be deleted at the end of the call unless p is
        // moved/copied elsewhere at some point
    }
};

int main()
{
    auto p = std::make_shared<foo>();
    p->bar(std::move(p));
    return 0;
}

Главный вопрос конкретно об этой строке:

p->bar(std::move(p));

Гарантируется ли это всегда захватывать текущее значение p.operator->() перед построением Аргумент? Или это могло произойти после перемещения от p?

(Примечание: я уверен, что это безопасно для аргумента std::shared_ptr<foo>&&, поскольку тогда фактическая конструкция перемещения не происходит, пока внутри тела метода , если вообще. Но когда передано по значению, может ли конструкция аргумента [которая включает в себя конструкцию перемещения] произойти до вызова p.operator->() или всегда строго после?)

1 Ответ

4 голосов
/ 16 марта 2020

Если вы используете std::shared_ptr<foo>&& в качестве типа параметра (или любого ссылочного типа), тогда проблем не будет, потому что вызов std::move фактически не изменяет объект в любом случае. Не имеет значения, выполняется ли он первым.

До C ++ 17 вариант по значению небезопасен. Не существует правила секвенирования, которое гарантировало бы, что выражение, называющее функцию, будет оценено перед инициализацией параметров функции. Таким образом, построение перемещения параметра функции может произойти до того, как p->bar будет оценено.

Начиная с C ++ 17, вычисление значения и все побочные эффекты постфиксного выражения, именующего функцию, секвенируются до вычисления значения и побочные эффекты всех выражений в аргументах вызова, что подразумевает, что конструктор параметра функции секвенируется после вычисления p->bar. См. [expr.call] / 5 . Поэтому потенциально проблематичный c operator-> вызов на p происходит первым, до создания перемещения, что делает код безопасным.

Те же утверждения сохраняются, если вы замените std::shared_ptr на std::unique_ptr.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...