将 std::string ctor 参数传递给具有移动语义的 pimpl 中的 impl

Posted

技术标签:

【中文标题】将 std::string ctor 参数传递给具有移动语义的 pimpl 中的 impl【英文标题】:Pass a std::string ctor parameter to impl in pimpl with move semantics 【发布时间】: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,否则它们永远不会被移动。该语句有几个边缘情况,但它们处理具有自动存储持续时间的本地对象,并且要么被返回,要么被抛出本地范围之外。 【参考方案1】:

这是正确的做法吗

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

这很好。

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

Impl(string&& s)

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


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

【讨论】:

以上是关于将 std::string ctor 参数传递给具有移动语义的 pimpl 中的 impl的主要内容,如果未能解决你的问题,请参考以下文章

将 std::map 对象传递给线程

EXC_BAD_ACCESS(code = 1,address = 0x0)当将std :: map作为参数传递给虚拟函数调用时发生

如何将 POST 参数传递给 Durable Function,然后将此参数传递给 Timer Triggered 函数

如何将参数传递给 Java 线程?

如何将参数传递给进程

如何通过反射将参数传递给方法