【问题标题】:Pass a std::string ctor parameter to impl in pimpl with move semantics将 std::string ctor 参数传递给具有移动语义的 pimpl 中的 impl
【发布时间】:2021-10-18 21:30:28
【问题描述】:

这是通过移动语义将 std::string 参数传递给 Impl 的构造函数的正确方法吗?

#include <string>
#include <memory>

using namespace std;

class Foo
{
    struct Impl;
    unique_ptr<Impl> impl_;
public:
    Foo(string s);
};

struct Foo::Impl
{
    string s_;
    Impl(string s) : s_(std::move(s)) {}
};

Foo::Foo(string s) : impl_(make_unique<Foo::Impl>(move(s)))
{
}

或者应该将Impl的ctor定义为:

Impl(string&& s) : s_(std::move(s)) {}

【问题讨论】:

  • 使用右值引用可能会使代码更快一点,因为它会减少移动。与往常一样,尝试两者并衡量结果。根据字符串的大小,以及如果您使用 SSO 实现,删除一个移动可能会产生很大的不同,或者它可能并不重要。
  • 对于右值参考案例,我需要 Impl 的 ctor 中的 std::move() 吗?无论有没有移动调用,它都可以编译。
  • 是的,您仍然需要使用std::move。任何有名字的东西都是左值,包括右值引用,所以如果你想让移动发生,你需要用std::move将它转换回右值。
  • 我明白了,所以没有 std::move() s_ 只会被复制构造?
  • 是的。没有它,你就有了一个左值,除非你使用std::move,否则它们永远不会被移动。该语句有几个边缘情况,但它们处理具有自动存储持续时间的本地对象,并且要么被返回,要么被抛出本地范围之外。

标签: c++ c++11 move-semantics


【解决方案1】:

这是正确的做法吗

Impl(string s) : s_(std::move(s)) {}

这很好。

或者应该将Impl的ctor定义为:

Impl(string&& s)

这通常不太有用,因为您无法将左值字符串作为参数传递。也就是说,如果 Foo::Foo(string s) 是调用 Impl 的构造函数的唯一上下文,那么在实践中缺乏一般用途不会成为问题,因此这也可以。


附:一旦您在单独的翻译单元中实际定义了Impl,您会发现您需要用户声明Foo 的特殊成员函数(析构函数、移动、赋值),因为它们的定义取决于Impl 的定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    • 2021-04-22
    • 2015-11-20
    • 2021-12-30
    • 2021-11-07
    • 2012-12-27
    • 2020-04-20
    相关资源
    最近更新 更多