繁体   English   中英

在unique_ptr中包装一个没有移动构造函数的C++对象?

[英]Wrap a C++ object without move constructor in a unique_ptr?

所以总的来说,我对移动语义和现代 C++ 还很陌生,但据我所知,我可以编写如下代码

Foo doSomething(Bar b) {
    Foo f{b};
    return f;
}

请注意,我没有明确编写 std::move 来允许编译器应用 RVO。

我不想修改 Foo 或 Bar 并且编译器因Call to implicitly-deleted copy constructor of 'Foo'失败。

所以我试图通过引入一个动作来解决这个问题:

Foo doSomething(Bar b) {
    Foo f{b};
    return std::move(f);
}

哪个失败并出现相同的错误。 (额外问题:当我想移动 Foo 时,为什么编译器会抱怨复制构造函数?)

所以我的想法是将 Foo 包装在std::unique_ptr ,我的问题是这是否是修复它的“正确”方法。

std::unique_ptr<Foo> doSomething(Bar b) {
    auto f = std::make_unique<Foo>(b);
    return f;
}

额外问题:当我想移动 Foo 时,为什么编译器会抱怨复制构造函数?

当 Foo 既不可移动也不可复制时,编译器可能会这样做。

所以我的想法是将 Foo 包装在 std::unique_ptr 中,我的问题是这是否是修复它的“正确”方法。

您可能应该返回一个纯右值:

Foo doSomething(Bar b) {
    return Foo{b};
}

请注意,如果 Foo 不能移动,这需要 C++17 才能工作。 Pre-C++17,“正确”的方式取决于上下文。 唯一指针可能没问题,或者不首先编写函数。

据我了解。

传统上返回值优化就是这样,一种优化(尽管可能会改变程序的行为)。 因此复制构造函数必须可用(而不是“删除”),即使编译器最终决定不需要使用它。

C++11 引入了移动语义,其中一部分是允许在返回值时使用移动构造函数的特殊规则。 因此,您可以返回可以移动但不能以正常方式复制的类型,而不必显式使用 std::move。

C++17 更改了匿名返回值的规则,以保证它们是无复制的*,并且不再需要复制或移动构造函数。 然而,它没有解决更复杂的命名返回值问题。

有一个解决命名返回值问题的建议( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2025r0.html ),但我不知道它是否会被接受。

包装在 unique_ptr 中确实是一种有效地将不可移动对象转换为可移动对象的方法,但这也意味着该对象存储在堆中而不是堆栈中。 在堆上存储对象有利有弊,一方面,在大多数系统上,堆空间通常比可用的堆栈空间更多,另一方面,在堆上分配和释放内存比在堆栈上更昂贵,并且额外的间接级别也有一些成本。

额外问题:当我想移动 Foo 时,为什么编译器会抱怨复制构造函数?

std::move 实际上并没有移动任何东西,它只是将左值引用更改为右值引用。 如果存在移动构造函数,则 std::move 将使其被用于支持复制构造函数,但如果不存在移动构造函数,则 std::move 不会停止使用复制构造函数。

* 出于 ABI 兼容性(以及潜在的性能)原因,对于可简单复制的类型,此规则有一个例外。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM