【问题标题】:Efficient way to construct object with string member用字符串成员构造对象的有效方法
【发布时间】:2019-09-16 08:08:59
【问题描述】:

假设我有一个班级ThisHasAStringMember。假设它有一个私有成员,它是一个字符串,我想有效地获取字符串值,在可能的情况下更喜欢移动而不是副本。下面的两个构造函数能做到吗?

class ThisHasAStringMember
{
public:
  // ctors
  ThisHasAStringMember(const std::string str) : m_str(str) {}
  ThisHasAStringMember(std::string &&str) : m_str(std::move(str)) {}

  // getter (no setter)
  std::string value() { return m_str; }
private:
  std::string m_str;
}

在第二个构造函数中,str 参数之前是否需要双 & 号?

这是实现此目的的正确方法吗?

【问题讨论】:

  • 如果你有 1 小时的时间,试试这个 CPPCON 视频^^。 youtube.com/watch?v=PNRju6_yn3o 。 TLDR : 就价值而言非常好(不是完美但很好)
  • Move 无论如何都会被任何体面的现代编译器选择。您不需要那个显式的构造函数声明。顺便说一句,我已经看到了您的最后一个问题,您不应该对这些事情束手无策。您可以确信现代编译器会尽可能高效地完成这些工作。
  • 如果它应该是有效的..你确定要返回字符串对象的副本而不是对它的引用吗?
  • @MartinMorterol 我没有花整个小时,而是 30 分钟。如果没有时间 10 分钟就足以注意到大多数问题都来自没有显式构造函数。

标签: c++ c++11 constructor move


【解决方案1】:

起初我会注意到最好将构造函数标记为显式。

接下来最好将解决方案中的第一个构造函数更改为采用 const 引用以避免复制左值:

// ctors
ThisHasAStringMember(const std::string& str) : m_str(str) {}
ThisHasAStringMember(std::string &&str) : m_str(std::move(str)) {}

从性能的角度来看,这种方法是最佳的(您将对左值调用一个复制构造函数,对右值调用一个移动构造函数),但是在这种情况下每次实现两个构造函数是很无聊的。如果你有 N 个成员 - 2^N 个构造函数。

有几个选择:

  1. Signle 构造函数,您可以在其中仅按值传递参数。是的,它在 C++98 中效率不高,但在 C++11 中,当您创建完整副本时 - 这是一个选项。

    ThisHasAStringMember(std::string str) : m_str(std::move(str)) {}

当传递左值时,将有一个复制构造函数调用和一个移动构造函数调用。当传递右值时,将有两个移动构造函数调用。是的,在每种情况下,您都有一个额外的移动构造函数调用。但它通常很便宜(甚至可以被编译器优化掉)而且代码也很简单。

  1. 通过右值传递参数的单个构造函数:

    ThisHasAStringMember(std::string&& str) : m_str(std::move(str)) {}

如果你传递左值,你必须先明确地将它复制到调用的地方,例如 ThisHasAStringMember(复制(someStringVar))。 (这里copy是一种简单的模板复制方法)。而且你仍然会有一个额外的左值移动构造函数调用。对于右值,不会有任何开销。我个人喜欢这种方法:所有复制参数的地方都是明确的,你不会在性能关键的地方偶尔复制。

  1. 制作构造函数模板并使用完美转发:
template <typename String, 
    std::enable_if_t<std::is_constructible_v<std::string, String>>* = nullptr>
ThisHasAStringMember(String&& str) : m_str(std::forward<String>(str))
{}

右值和左值都没有开销,但在大多数情况下,您需要制作构造函数模板并在标题中定义它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    相关资源
    最近更新 更多