我想在C++中模拟 Rustbar(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
的生命周期被"转移"到some_func
,我们不能再使用foo
了。如果转换器函数继承了foo
的资源,则应以这种方式设计b
。在我的情况下,我希望some_func
成为foo
的实例方法。仅此而已。
我假设您希望测试用例中的这一行有效:
Bar b = Foo().bar();
你希望它的效果是b
有一个std::unique_ptr<Foo>
可以玩。
如果是这种情况,您将不得不实现bar
来创建新的Foo
instace,因为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 所做的一切都是转换为右值引用,以便可以调用采用右值引用参数的适当函数。
据我所知,您无法从对象本身中延长对象的生存期。 在您提供的示例中,您正在创建一个类 Foo 的临时对象,一旦 bar(( 返回,该对象将被销毁。
您可以做的一件事是声明您的 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的对象,并且您正在唯一指针周围移动您想要拥有您的实例的任何对象。