在std :: move()之后unique_ptr会发生什么?

时间:2016-03-17 20:37:23

标签: c++ unique-ptr

这段代码就是我想要的:

Tony& Movie::addTony()
{
    Tony *newTony = new Tony;
    std::unique_ptr<Tony> tony(newTony);
    attachActor(std::move(tony));
    return *newTony;
}

我想知道我是否可以这样做:

Tony& Movie::addTony()
{
    std::unique_ptr<Tony> tony(new Tony);
    attachActor(std::move(tony));
    return *tony.get();
}

但是*tony.get()会是同一个指针还是null?我知道我可以验证,但它的标准是什么?

3 个答案:

答案 0 :(得分:23)

不,你不能这样做。移动unique_ptr使其为空。如果没有,那么它就不会是唯一的。我当然假设attachActor没有像这样愚蠢的事情:

attachActor(std::unique_ptr<Tony>&&) {
    // take the unique_ptr by r-value reference,
    // and then don't move from it, leaving the
    // original intact
}

第20.8.1节第4段。

  

此外,u(unique_ptr对象)可以根据请求进行传输   所有权到另一个唯一指针u2。完成这样的   转移,以下后置条件成立:
   - u2.p等于转移前的u.p,
   - u.p等于nullptr
   - 如果预转移u.d维持状态,则此类状态已转移到u2.d.

答案 1 :(得分:10)

标准说{§20.8.1.2.1¶16,强调增加了'std::unique_ptr的移动构造函数

unique_ptr(unique_ptr&& u) noexcept;
     

通过将所有权unique_ptr构建为u*this

因此,在移动构造作为参数传递给attachActor的{​​{1}}形式的临时对象后,tony不再拥有该对象,因此tony。 (这是标准库实际上对移出对象的状态进行断言的少数情况之一。)

但是,无需借助裸tony.get() == nullptr和原始指针即可实现返回引用的愿望。

new

此代码假定Tony& Movie::addTony() { auto tony = std::make_unique<Tony>(); auto p = tony.get(); attachActor(std::move(tony)); return *p; } 不会将其参数丢弃在地板上。否则,指针attachActor会在p attachActor之后悬挂。如果不能依赖它,则必须重新设计界面并使用共享指针。

return

答案 2 :(得分:0)

move之后,将unique_ptr设置为nullptr。最后,我认为这取决于attachActor的工作方式,但是,在许多情况下,一种好的方法是使用 move语义来确保Tony始终拥有单一所有权,这是减少某些类型错误的风险的方法。我的想法是尝试模仿所有权和向Rust借钱。

    #include <string>
    #include <memory>
    #include <vector>
    #include <iostream>
    
    
    using namespace std;
    
    class Tony {
        public:
            string GetFullName(){
                return "Tony " + last_name_;
            }
            void SetLastName(string lastname) {
                last_name_ = lastname;
            }
        private:
            string last_name_;
    };
    
    class Movie {
        public:
            unique_ptr<Tony> MakeTony() {
                auto tony_ptr = make_unique<Tony>();
                auto attached_tony_ptr = AttachActor(move(tony_ptr));
                return attached_tony_ptr;
            }
            vector<string> GetActorsList(){
                return actors_list_;
            }
    
        private:
            unique_ptr<Tony> AttachActor(unique_ptr<Tony> tony_ptr) {
                tony_ptr->SetLastName("Garcia");
                actors_list_.push_back(tony_ptr->GetFullName());
                return tony_ptr;   // Implicit move
            }
    
            vector<string> actors_list_;
    };
    
    
    int main (int argc, char** argv) {
        auto movie = make_unique<Movie>();
        auto tony = movie->MakeTony();
        cout << "Newly added: " << tony->GetFullName() << endl;
        for(const auto& actor_name: movie->GetActorsList()) {
            cout << "Movie actors: " << actor_name << endl;
        }
    }