为什么我不能用函数返回的unique_ptr交换另一个unique_ptr?

3
以下代码会抛出一个警告:
警告 C4239:使用了非标准扩展:'argument':从 'std::unique_ptr<_Ty>' 转换为 'std::unique_ptr<_Ty> &'
std::unique_ptr<T> foo() { return std::unique_ptr<T>( new T ); }
std::unique_ptr<T> myVar;
myVar.swap(foo());

我想知道应该如何妥善处理这种情况。
3个回答

10
std::unique_ptrswap 成员函数接受非常量左值引用,表达式 foo() 是一个右值,因为 foo 是返回对象(而不是引用)的函数。你不能将右值绑定到非常量左值引用。
请注意,你可以反过来交换:
foo().swap(myVar);

更简单的方法是直接初始化:
std::unique_ptr<T> myVar(foo());

1
很遗憾,Visual Studio不支持统一初始化语法。 - Praetorian
@Prætorian:打扰了,让我来修复一下。 - CB Bailey

1

std::unique_ptr::swap 接受一个非 const 引用作为另一个指针。你不能将 r-value 绑定到非 const 引用,尽管 VC++ 通过非标准扩展允许这样做。因此会出现警告。

要消除警告,请将 foo 的返回值存储在变量中,然后进行交换,或者反转交换的顺序。

foo().swap( myVar );

1

您正在尝试交换到一个临时变量。您可以尝试使用以下方法:

std::unique_ptr<T> foo() { return std::unique_ptr<T>( new T ); }
std::unique_ptr<T> myVar1;
std::unique_ptr<T> myVar2 = foo();
myVar1.swap(myVar2);
注意:这与std::unique_ptr无关。出于同样的原因,以下内容也是不合法的:
void foo(std::string& s) { .... }
std::string bar() { .... }

foo(bar());

将数据交换到临时变量中有什么问题?这在VS11中并不是一个警告。 - aCuria
1
@aCuria 这种语言不允许将非 const 引用绑定到临时对象。这样做的逻辑是因为改变即将消失的东西没有意义。 - juanchopanza
谢谢您的回复,但在我的情况下,让它立即消失(dtor被调用)是有意义的。我正在使用它来管理图形资源(比如纹理),这些资源应该是屏幕大小的。当屏幕分辨率改变时,旧的纹理应该被新的替换,并且旧的纹理应该被销毁... 因此,我想做的是texture.swap(newtexture); - aCuria

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接