如何将 "this" 的生命周期移动到 C++ 中的另一个对象中?
How to move lifetime of "this" into another object in C++?
我想在 C++ 中模拟 Rust bar(self, ...)
函数,所以我这样写:
class Foo;
class Bar {
public:
explicit Bar(unique_ptr<Foo> foo);
private:
unique_ptr<Foo> _foo;
};
class Foo {
public:
Bar bar() {
return Bar(unique_ptr<Foo>(this));
}
};
Bar::Bar(unique_ptr<Foo> foo) : _foo(move(foo)) {}
TEST_CASE("Convert a Foo object into a Bar object") {
Bar b = Foo().bar();
}
此代码段会引发段错误。因为 Foo()
和 b
都认为他们拥有 Foo
的实例并且它会被清理两次。如何解决?
我会描述我想做什么。在以下代码中:
auto foo = unique_ptr<Foo>(new Foo());
Bar b = some_func(move(foo));
调用some_func
后,foo
的生命周期为"transferred"到some_func
,我们不能再使用foo
了。如果 b
继承了 foo
的资源,转换器函数应该这样设计。在我的情况下,我希望 some_func
成为 foo
的实例方法。就是这样。
我假设您希望测试用例中的这一行有效:
Bar b = Foo().bar();
你希望它的效果是 b
得到一个 std::unique_ptr<Foo>
来玩。
如果是这种情况,您将必须实施 bar
来创建 Foo
的新实例,因为 Foo()
是临时的,其生命周期不能像您那样动态变化很想。您在评论中提到 Foo
无法复制,但大概可以移动:
class Foo {
public:
Bar bar() && {
return Bar(std::make_unique<Foo>(std::move(*this)));
}
};
请注意,我使 bar
右值限定,因此它不能在左值上调用(因为它从 *this
移动)。要在左值上调用它,你必须从它 move
:
Foo().bar(); // rvalue calls are fine
Foo f;
std::move(f).bar(); // lvalue must be moved
您似乎混淆了 std::move 在做什么,并假设它转移了对象所有权。
它没有。
std::move所做的一切都是转换为右值引用,以便可以调用采用右值引用参数的适当函数。
据我所知,您不能从对象本身延长对象的生命周期。
在您提供的示例中,您正在创建 class Foo 的临时对象,它将在 bar() returns.
后立即销毁
您可以做的一件事是声明您的 some_func 函数以获取右值引用,如下所示:
Bar some_func(std::unique_ptr<Foo>&& someFoo)
{
Bar someBar(std::move(someFoo));
return someBar;
}
int main() {
auto foo = std::make_unique<Foo>();
//do stuff with foo
Bar b = some_func(std::move(foo));
//foo is now invalid, and can't be used;
//b has ownership of foo
return 0;
}
我不确定这是否回答了您的问题并达到了您的预期。要点是,您不是创建一个临时对象,而是使用 make_unique 创建一个对象,并且您正在围绕唯一指针移动到您想要拥有您的实例的任何对象。
我想在 C++ 中模拟 Rust bar(self, ...)
函数,所以我这样写:
class Foo;
class Bar {
public:
explicit Bar(unique_ptr<Foo> foo);
private:
unique_ptr<Foo> _foo;
};
class Foo {
public:
Bar bar() {
return Bar(unique_ptr<Foo>(this));
}
};
Bar::Bar(unique_ptr<Foo> foo) : _foo(move(foo)) {}
TEST_CASE("Convert a Foo object into a Bar object") {
Bar b = Foo().bar();
}
此代码段会引发段错误。因为 Foo()
和 b
都认为他们拥有 Foo
的实例并且它会被清理两次。如何解决?
我会描述我想做什么。在以下代码中:
auto foo = unique_ptr<Foo>(new Foo());
Bar b = some_func(move(foo));
调用some_func
后,foo
的生命周期为"transferred"到some_func
,我们不能再使用foo
了。如果 b
继承了 foo
的资源,转换器函数应该这样设计。在我的情况下,我希望 some_func
成为 foo
的实例方法。就是这样。
我假设您希望测试用例中的这一行有效:
Bar b = Foo().bar();
你希望它的效果是 b
得到一个 std::unique_ptr<Foo>
来玩。
如果是这种情况,您将必须实施 bar
来创建 Foo
的新实例,因为 Foo()
是临时的,其生命周期不能像您那样动态变化很想。您在评论中提到 Foo
无法复制,但大概可以移动:
class Foo {
public:
Bar bar() && {
return Bar(std::make_unique<Foo>(std::move(*this)));
}
};
请注意,我使 bar
右值限定,因此它不能在左值上调用(因为它从 *this
移动)。要在左值上调用它,你必须从它 move
:
Foo().bar(); // rvalue calls are fine
Foo f;
std::move(f).bar(); // lvalue must be moved
您似乎混淆了 std::move 在做什么,并假设它转移了对象所有权。 它没有。
std::move所做的一切都是转换为右值引用,以便可以调用采用右值引用参数的适当函数。
据我所知,您不能从对象本身延长对象的生命周期。 在您提供的示例中,您正在创建 class Foo 的临时对象,它将在 bar() returns.
后立即销毁您可以做的一件事是声明您的 some_func 函数以获取右值引用,如下所示:
Bar some_func(std::unique_ptr<Foo>&& someFoo)
{
Bar someBar(std::move(someFoo));
return someBar;
}
int main() {
auto foo = std::make_unique<Foo>();
//do stuff with foo
Bar b = some_func(std::move(foo));
//foo is now invalid, and can't be used;
//b has ownership of foo
return 0;
}
我不确定这是否回答了您的问题并达到了您的预期。要点是,您不是创建一个临时对象,而是使用 make_unique 创建一个对象,并且您正在围绕唯一指针移动到您想要拥有您的实例的任何对象。