在 std::move() 之后 unique_ptr 会发生什么?
What happens to unique_ptr after std::move()?
这段代码是我想要做的:
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?我知道我可以验证,但它的标准做法是什么?
不,你不能那样做。移动 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 段
Additionally, u (the unique_ptr object) can, upon request, transfer
ownership to another unique pointer u2. Upon completion of such a
transfer, the following postconditions hold:
-- u2.p is equal to the pre-transfer u.p,
-- u.p is equal to nullptr, and
-- if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
标准说(§ 20.8.1.2.1 ¶ 16,强调已添加)std::unique_ptr
的移动构造函数
unique_ptr(unique_ptr&& u) noexcept;
Constructs a unique_ptr
by transferring ownership from u
to *this
.
因此,在您移动构建作为参数传递给 attachActor
的临时对象后,形成您的 tony
,tony
不再拥有该对象,因此 tony.get() == nullptr
. (这是标准库实际对移出对象的状态做出断言的少数情况之一。)
但是,return 引用的愿望可以在不诉诸裸 new
和原始指针的情况下实现。
Tony&
Movie::addTony()
{
auto tony = std::make_unique<Tony>();
auto p = tony.get();
attachActor(std::move(tony));
return *p;
}
此代码假定 attachActor
不会将其论点放在地板上。否则,指针 p
会在 attachActor
完成 return
后悬空。如果不能依赖这一点,您将不得不重新设计您的界面并改用共享指针。
std::shared_ptr<Tony>
Movie::addTony()
{
auto tony = std::make_shared<Tony>();
attachActor(tony);
return tony;
}
在move
之后,unique_ptr
设置为nullptr
。最后,我认为这取决于 attachActor
在做什么,但是,在许多情况下,一个好的方法是使用 移动语义 来保证 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;
}
}
这段代码是我想要做的:
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?我知道我可以验证,但它的标准做法是什么?
不,你不能那样做。移动 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 段
Additionally, u (the unique_ptr object) can, upon request, transfer ownership to another unique pointer u2. Upon completion of such a transfer, the following postconditions hold:
-- u2.p is equal to the pre-transfer u.p,
-- u.p is equal to nullptr, and
-- if the pre-transfer u.d maintained state, such state has been transferred to u2.d.
标准说(§ 20.8.1.2.1 ¶ 16,强调已添加)std::unique_ptr
unique_ptr(unique_ptr&& u) noexcept;
Constructs a
unique_ptr
by transferring ownership fromu
to*this
.
因此,在您移动构建作为参数传递给 attachActor
的临时对象后,形成您的 tony
,tony
不再拥有该对象,因此 tony.get() == nullptr
. (这是标准库实际对移出对象的状态做出断言的少数情况之一。)
但是,return 引用的愿望可以在不诉诸裸 new
和原始指针的情况下实现。
Tony&
Movie::addTony()
{
auto tony = std::make_unique<Tony>();
auto p = tony.get();
attachActor(std::move(tony));
return *p;
}
此代码假定 attachActor
不会将其论点放在地板上。否则,指针 p
会在 attachActor
完成 return
后悬空。如果不能依赖这一点,您将不得不重新设计您的界面并改用共享指针。
std::shared_ptr<Tony>
Movie::addTony()
{
auto tony = std::make_shared<Tony>();
attachActor(tony);
return tony;
}
在move
之后,unique_ptr
设置为nullptr
。最后,我认为这取决于 attachActor
在做什么,但是,在许多情况下,一个好的方法是使用 移动语义 来保证 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;
}
}