编译器可以省略特定数据成员的副本吗?

Can the compiler elide copies of specific data members?

提问人:TwistedBlizzard 提问时间:8/30/2023 最后编辑:TwistedBlizzard 更新时间:8/30/2023 访问量:42

问:

获取此代码:

struct Bar { //has non-default copy-constructor
    Bar() = default;
    Bar(const Bar&) {} 
};
struct LargeObject { //has default copy-constructor
    std::array<char, 1000> m_chars;
};
struct Foo {
    Bar m_bar;
    LargeObject m_obj;
};
Foo func() { Foo f; return f; } 

当用户指定复制构造函数时,编译器无法省略副本。当类的成员具有非默认复制构造函数时,该怎么办?在这段代码中,当从 返回时,编译器可以省略 的副本还是必须复制所有内容?ffuncm_obj

C++ 移动语义

评论

0赞 NathanOliver 8/30/2023
如果被复制,它的所有成员都将被复制。Foo
0赞 463035818_is_not_an_ai 8/30/2023
复制使源保持不变,不移动,因此在复制 a 时移动一个成员是错误的Foo
0赞 TwistedBlizzard 8/30/2023
@463035818_is_not_an_ai 如果要从函数返回本地 Foo,该怎么办?那样的话就不重要了吗?
0赞 463035818_is_not_an_ai 8/30/2023
我只是参考你写的东西。当你移动一个时,成员可以被移动,但当你复制一个时,你需要复制它们。FooFoo
1赞 463035818_is_not_an_ai 8/30/2023
复制省略是在某些情况下发生的情况,但您不会显示任何可以省略副本的代码。难道你在问编译器生成的复制和移动将做什么吗?如目前所述,很难理解您在问什么 - 编辑:好的,现在稍微好一点Foo

答:

3赞 ShadowRanger 8/30/2023 #1

你的问题是基于一个错误的前提。编译器完全有权省略这样的副本,无论类本身或其成员之一是否具有非默认的复制(或移动)构造函数。自 C++ 11 以来引入的复制省略规则的好处是允许这种优化,即使它违反了假设规则。

如果它不能做到这一点,那么复制省略就不会那么有用;即使具有单个智能指针(具有自定义复制和移动构造函数)的类也不符合 RVO 的条件,除非编译器可以肯定地证明没有违反假设规则。

在特定方案中,编译器通常可以通过直接将对象构造到调用方提供的存储中来实现(并且启用优化后,这不是强制性的,因为您依赖于非强制性 NRVO,而不是简单 RVO 的 C++17 保证复制省略)来实现,而无需使用必须移动/复制回调用方的单独对象。funcFooFoo f