为什么 std::unique_ptr<>.release() 在赋值左侧的成员函数访问之前被评估?

May*_*rni 9 c++ c++20

当访问 unique_ptr->get_id() 时,这会导致分段错误,因为 release() 是预先运行的。

这里不保证顺序吗?

#include <iostream>
#include <memory>
#include <unordered_map>

class D
{
private:
        int id_;
public:
        D(int id) : id_{id} { std::cout << "D::D\n"; }
        ~D() { std::cout << "D::~D\n"; }

        int get_id() { return id_; }

        void bar() { std::cout << "D::bar\n"; }
};

int main() {
        std::unordered_map<int, D*> obj_map;
        auto uniq_ptr = std::make_unique<D>(123);

        obj_map[uniq_ptr->get_id()] = uniq_ptr.release();
        obj_map.at(123)->bar();

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ica 15

这是因为[expr.ass]/1指出:

[...] 在所有情况下,赋值都是在右操作数和左操作数的值计算之后、赋值表达式的值计算之前进行排序的。右操作数排在左操作数之前。对于不确定顺序的函数调用,复合赋值操作是一次计算。

强调我的

根据上面的内容,首先评估右侧,然后评估左侧,然后进行分配。应该注意的是,这仅从 C++17 开始得到保证。在 C++17 之前,未指定左侧和右侧计算的顺序。


Jon*_* S. 13

实际上可以保证这段代码总是会失败

根据cppreference

  1. 在每个简单赋值表达式 E1=E2 和每个复合赋值表达式 E1@=E2 中,E2 的每个值计算和副作用都在 E1 的每个值计算和副作用之前排序 (C++17 起)

换句话说:在您的情况下release()保证会在之前被调用get_id()