首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11:按值调用、移动语义和继承

C++11:按值调用、移动语义和继承
EN

Stack Overflow用户
提问于 2013-05-24 03:48:47
回答 3查看 1.8K关注 0票数 4

假设我有一个类,我计划将其作为可实例化的类直接公开给程序员:

代码语言:javascript
复制
class Base
{
public:
    Base(std::string text) : m_text(std::move(text)) {}
private:
    std::string m_text;
};

到目前一切尚好。这里不需要rvalue构造函数。现在,在将来的某个时候,我决定扩展Base:

代码语言:javascript
复制
class Derived : public Base
{
public:
    Derived(const std::string &text) : Base(text) {}
};

这让我感到困惑:我不能在Derived中通过值来获取字符串,因为这就是Base已经在做的事情--我最终会得到2个副本和1个移动。这里的const-reference构造函数还对rvalue执行不必要的复制。

问题:如何在不添加更多构造函数的情况下只复制+移动一次(就像Base中的简单构造函数一样)?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-05-24 03:52:44

您不能只复制和移动一次,除非您更改类的设计,并将它们的构造函数转换为(可能受SFINAE约束的)模板化转发构造函数(Yakk's answer shows how)。

虽然这样做可以在提供右值时只执行一次移动而不执行复制,而在提供左值时只执行一次复制而不执行移动,但在大多数情况下这是一种过度的杀伤力。

作为基于模板的转发构造函数的替代方法,您可以在基类和派生类中提供两个构造函数:一个用于右值引用,另一个用于对const的左值引用。但是,在大多数情况下,这是一个不必要的复杂性(当参数数量增加时,也不能很好地扩展,因为所需构造函数的数量将呈指数级增加)。

移动std::string的速度与复制指针和整数一样快(这里忽略了单点登录优化),除非您有确凿的证据证明这是阻碍应用程序满足其性能要求的瓶颈(难以相信),否则您不应该为此而烦恼。

因此,只要让您的Derived构造函数无条件地按值接受其参数,并在将其传递给基类的构造函数时移动它:

代码语言:javascript
复制
class Derived : public Base
{
public:
    Derived(std::string text) : Base(std::move(text)) { }
};

如果您希望(或接受) Derive继承Base的所有构造函数,另一种选择是利用C++11继承的构造函数,如下所示:

代码语言:javascript
复制
class Derived : public Base
{
public:
    using Base::Base;
//  ^^^^^^^^^^^^^^^^^
};
票数 8
EN

Stack Overflow用户

发布于 2013-05-24 03:53:48

使用SFINAE构造函数实现完美的转发:

代码语言:javascript
复制
class Derived : public Base
{
public:
  template<
    typename T,
    typename=typename std::enable_if<
      std::is_constructible<std::string, T&&>::value
    >::type
  >
  Derived(T&& text) : Base(std::forward<T>(text)) {}
};

一个缺点(除了上述构造的疯狂之外)是,这将以过于贪婪的程度参与重载解析:对于任何可以转换为std::string的参数,它几乎都是完美的匹配。因此,如果您有另一个接受char const*的构造函数,那么如果您传入了一个char const*变量,那么它可能会被忽略,因为T&&可能匹配得更好。

如果你的DerivedBase有一个operator std::string...

票数 3
EN

Stack Overflow用户

发布于 2013-05-24 04:00:01

Derived更改为以下内容:

代码语言:javascript
复制
class Derived : public Base
{
public:
    using Base::Base;
};

现在,DerivedBase继承了构造函数。

有关详细信息,请参阅Forwarding all constructors in C++0x

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16722614

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档