标签: copy-elision

为什么返回参数时不允许使用RVO?

它在[C++ 11:12.8/31]中说明:

复制/移动操作的省略,称为复制省略,允许[...]:

- 在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(除函数或catch子句参数之外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作

这意味着

#include <iostream>

using namespace std;

struct X
{
    X() { }
    X(const X& other) { cout << "X(const X& other)" << endl; }
};

X no_rvo(X x) {
    cout << "no_rvo" << endl;
    return x;
}

int main() {
    X x_orig;
    X x_copy = no_rvo(x_orig);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

将打印

X(const X& other)
no_rvo
X(const X& other)
Run Code Online (Sandbox Code Playgroud)

为什么需要第二个拷贝构造函数?编译器不能简单地延长x的生命周期吗?

c++ return-value-optimization copy-elision rvo

21
推荐指数
2
解决办法
1870
查看次数

从工厂函数就地初始化不可复制的成员(或其他对象)

对于任何此语法,类必须具有有效的副本或移动构造函数才是合法的:

C x = factory();
C y( factory() );
C z{ factory() };
Run Code Online (Sandbox Code Playgroud)

在C++ 03中,依赖复制省略来阻止编译器触及复制构造函数是相当普遍的.无论定义是否存在,每个类都有一个有效的复制构造函数签名.

在C++ 11中,应该定义一个不可复制的类型C( C const & ) = delete;,无论使用什么,对函数的任何引用都是无效的(对于不可移动的相同).(C++11§8.4.3/ 2).例如,GCC会在尝试按值返回此类对象时抱怨.复制省立不再有帮助.

幸运的是,我们还有新的语法来表达意图而不是依赖于漏洞.该factory函数可以返回一个braced-init-list来临时构造结果:

C factory() {
    return { arg1, 2, "arg3" }; // calls C::C( whatever ), no copy
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果有任何疑问,此return语句解析如下:

  1. 6.6.3/2:"带有braced-init-list的return语句初始化了从指定的初始化列表中通过copy-list-initialization(8.5.4)从函数返回的对象或引用."
  2. 8.5.4/1:"复制初始化上下文中的列表初始化称为复制列表初始化." 3:"如果T是类类型,则考虑构造函数.枚举适用的构造函数,并通过重载解析(13.3,13.3.1.7)选择最佳构造函数."

不要被名称copy-list-initialization误导.8.5:

13:初始化的形式(使用括号或=)通常是无关紧要的,但是当初始化器或正在初始化的实体具有类类型时,它很重要; 见下文.如果正在初始化的实体没有类类型,则带括号的初始值设定项中的表达式列表应为单个表达式.

14:在表单 T x = a; 中以及在参数传递,函数返回,抛出异常(15.1),处理异常(15.3)和聚合成员初始化(8.5.1)时发生的初始化称为复制初始化.

当初始化器是braced-init-list时,复制初始化及其替代的直接初始化始终遵循列表初始化.添加时没有语义效果=,这是列表初始化非正式地称为统一初始化的一个原因.

存在差异:与复制初始化不同,直接初始化可以调用显式构造函数.复制初始化初始化临时并复制它以在转换时初始化对象.

的规范 …

c++ initialization copy-elision c++11

21
推荐指数
1
解决办法
2072
查看次数

为什么不使用`make_x()`函数尽可能省略移动构造函数?

我无法弄清楚为什么在最后一种情况下启用了复制省略时调用移动构造函数(甚至是强制性的,例如在C++ 17中):

class X {
  public:
    X(int i) { std::clog << "converting\n"; }
    X(const X &) { std::clog << "copy\n"; }
    X(X &&) { std::clog << "move\n"; }
};

template <typename T>
X make_X(T&& arg) {
  return X(std::forward<T>(arg));
}

int main() {
  auto x1 = make_X(1);    // 1x converting ctor invoked
  auto x2 = X(X(1));      // 1x converting ctor invoked
  auto x3 = make_X(X(1)); // 1x converting and 1x move ctor invoked
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,哪些规则阻碍了移动构造函数被省略?

UPDATE

调用移动构造函数时可能更直接的情况: …

c++ language-lawyer move-semantics copy-elision perfect-forwarding

21
推荐指数
2
解决办法
1250
查看次数

如何强制执行复制省略,为什么它不能与删除的复制构造函数一起使用?

我有一个无法上课的课程.复制这将是有问题的.我想保证它不会被复制,所以我制作了它的复制构造函数deleted:

class A {
  public:
    A();
    A(const A&) = delete;
};

A fun() {
  return A();
};

int main() {
  A a = fun();
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,g ++不能编译这个原因:

t.cc: In function ‘A fun()’:
t.cc:8:12: error: use of deleted function ‘A::A(const A&)’
   return A();
            ^
t.cc:4:5: note: declared here
     A(const A&) = delete;
     ^
t.cc: In function ‘int main()’:
t.cc:12:13: error: use of deleted function ‘A::A(const A&)’
   A a = fun();
             ^
t.cc:4:5: note: declared here
     A(const A&) …
Run Code Online (Sandbox Code Playgroud)

c++ copy-elision c++11

20
推荐指数
3
解决办法
2167
查看次数

GCC NRVO/RVO警告

是否有任何警告,让我们知道在海湾合作委员会中是否进行了NRVO/RVO

我发现-fno-elide-constructors关闭NRVO/RVO,但NRVO/RVO有自己的条件发生,有时不会发生.当需要额外的复制构造时,需要知道是否发生了NRVO/RVO.

我对编译时功能特别感兴趣.如果有一些特定的#pragma GCC...(它会立即激活诊断)或使用静态断言机制的东西会很好.

c++ gcc g++ copy-elision

19
推荐指数
2
解决办法
2473
查看次数

保证省略和链接函数调用

假设我有以下类型:

struct X {
    X& operator+=(X const&);
    friend X operator+(X lhs, X const& rhs) {
        lhs += rhs;
        return lhs;
    }
};
Run Code Online (Sandbox Code Playgroud)

我有声明(假设所有命名变量都是类型的左值X):

X sum = a + b + c + d;
Run Code Online (Sandbox Code Playgroud)

在C++ 17中,我对这个表达式执行的副本和移动有多少保证?那么无保障的省略呢?

c++ copy-elision c++17

18
推荐指数
2
解决办法
522
查看次数

在emplace()中创建对象时复制省略

我看到很多代码在工作中人们使用emplace和emplace_back与临时对象,如下所示:

struct A {
    A::A(int, int);
};

vector<A> v;
vector<A>.emplace_back(A(1, 2));
Run Code Online (Sandbox Code Playgroud)

我知道emplace_back的重点是能够直接传递参数,如下所示:

v.emplace_back(1, 2);
Run Code Online (Sandbox Code Playgroud)

但不幸的是,一些人并不清楚这一点.但是,我们不要纠缠于此......

我的问题是:编译器是否能够对此进行优化并跳过创建和复制?或者我应该真的尝试修复这些事件?

供您参考......我们正在使用C++ 14.

c++ copy-elision c++14

18
推荐指数
2
解决办法
967
查看次数

复制elision用于传值参数

特定

struct Range{
    Range(double from, double to) : from(from), to(to) {}
    double from;
    double to;
};

struct Box{
    Box(Range x, Range y) : x(x), y(y) {}
    Range x;
    Range y;
};
Run Code Online (Sandbox Code Playgroud)

假设我们跑了Box box(Range(0.0,1.0),Range(0.0,2.0)).

启用优化的现代编译器是否可以避免Range在此构造期间完全复制对象?(即构建Range内部的对象box以开始?)

c++ pass-by-value copy-elision

17
推荐指数
3
解决办法
3167
查看次数

当使用 std::make_pair 从函数返回一对时,为什么结构化绑定不会发生 RVO?

考虑这段代码,它定义了一个简单的结构Test(带有默认构造函数和复制构造函数)并std::pair <Test, Test>从函数返回 a 。

#include <iostream>
#include <utility>

using namespace std;

struct Test {
    Test() {}
    Test(const Test &other) {cout << "Test copy constructor called\n";}
};

auto func() {
    return make_pair(Test(), Test());
}

int main()
{
    auto [a, b] = func(); // Expectation: copies for a and b are both elided

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,输出是

Test copy constructor called
Test copy constructor called
Run Code Online (Sandbox Code Playgroud)

而修改func

Test copy constructor called
Test copy constructor called
Run Code Online (Sandbox Code Playgroud)

导致复制构造函数未被调用。我的 …

c++ return-value-optimization copy-elision c++17

17
推荐指数
3
解决办法
774
查看次数

'保证复制Elision'(P0135,C++ 1z)可能需要ABI破损吗?

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

上述"保证副本Elision"提案在2016年6月在芬兰奥卢举行的会议上被投票选入C++工作文件,然后被投票作为委员会草案出版.希望明年能够成为C++ 17标准的出版物.

该提案阐明了涉及临时对象的各种值类别,以在某些用例中强制执行复制构造函数调用.

我的问题是"这些新要求可能会破坏编译器的ABI兼容性,这些编译器可能以前没有在这些情况下完成复制,或者是以不符合新要求的方式实现的吗?"

我正在考虑初始化之类的东西,当创建对象时可以内联,而不是在跨越编译单元边界时.

c++ abi language-lawyer copy-elision c++17

16
推荐指数
1
解决办法
690
查看次数