在继承层次结构中复制和移动
Copy and move through inheritance hierarchy
考虑一个简单的
class Foo
{
public:
Foo(const std::string& name) : _name{name}
private:
std::string _name;
};
我们知道可以通过复制和移动进行优化
class Foo
{
public:
Foo(std::string name) : _name{std::move(name)}
private:
std::string _name;
};
但现在考虑一下层次结构:
class Base
{
protected:
Base(const std::string& name) : _name{name}
private:
std::string _name;
};
class Derived : public Base
{
public:
Derived(const std::string& name) : A(name) {}
};
class Derived2 : public Derived
{
public:
Derived2(const std::string& name) : Derived(name) {}
};
在这里实现复制和交换习惯用法的正确方法是什么?使用复制和交换而不是传递const引用是否有意义?
编辑:请解释否决票。
通过const-reference仍然是传统智慧
而且在所有可能的情况下都会继续,请参阅与此相关的代码指南。
不管你在博客等上读到了什么,你都应该坚持为所有复制成本可能很高的对象的正常用例传递const引用——从语义上讲,你不需要担心X类型如何执行移动和复制。这仍然是推荐的传统智慧,并为后期更改实现提供了所需的灵活性。如果将代码内联在头中,那么任何优秀的编译器都可以优化它(如果不在头中的话,也可以使用整个程序优化(。
此外,使用复制和移动只是(有时(对右值更快,而不是对左值。lvalues现在的情况实际上更糟了,必须先复制一个对象,然后再移动它
std::string
在这里特别有趣,因为小字符串优化-所以对于许多小字符串来说,在最坏的情况下,性能下降接近2倍。为什么?对于小字符串,移动和复制一样昂贵,移动或复制都不是微不足道的,这意味着如果使用复制和移动习惯用法,则会错过优化。
在链接到commments的帖子中,作者还必须写道:
同样,这是一种廉价的恒定时间操作,而复制是一种线性时间运算,因此在许多情况下这将是一个很好的价格值得付出。
此外,并非所有类型的移动都很便宜(例如std::array
(。
如果并且仅当,您已经在探查器中显示了这一点,并且您仍然非常关注它-那么您可能希望使用转发引用&&
而不是纯副本(如果不是,则解决方案是第三方(-然后调用std::forward
来转发到基类(完美转发(。
相关文章:
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 为什么复制而不是移动数据元素?
- 使lambda不可复制/不可移动
- 复制和交换习惯用法与移动操作之间的交互
- 为什么调用复制构造函数而不是移动构造函数?
- 隐式移动与复制操作和遏制
- 具有已删除移动和复制构造函数的类的就地构造
- 使用移动和复制语义时函数匹配如何工作?
- 直接初始化不可复制、不可移动的成员,而不使用聚合初始化
- 包装二进制缓冲区 - 可能没有多余的移动/复制?
- 当使用三元运算符并删除移动/复制CTOR时,Visual Studio不执行RVO
- 我们是否应该从派生类调用基类移动复制/分配构造函数
- 具有unique_ptr成员变量的 C++ 移动/复制/赋值<AbstractClass>
- 返回带有已删除移动/复制 ctor 的类型临时
- 消除默认/删除移动/复制语义中涉及的样板的好方法是什么
- C++11:移动/复制构造不明确
- 关于移动/复制c++对象实例
- 我丢失了一个移动/复制赋值
- 如何创建一个不可移动/复制构造的对象数组
- 编译器何时在C++中移动/复制