标签: copy-elision

'保证复制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
查看次数

复制省略是否适用于结构化绑定

强制复制省略是否适用于通过结构化绑定进行分解?以下哪种情况适用于?

// one
auto [one, two] = std::array<SomeClass>{SomeClass{1}, SomeClass{2}};

// two
auto [one, two] = std::make_tuple(SomeClass{1}, SomeClass{2});

// three
struct Something { SomeClass one, two; };
auto [one, two] = Something{};    
Run Code Online (Sandbox Code Playgroud)

我怀疑只有第三种情况允许复制省略,因为前两个会被"分解"通过std::get<>std::tuple_size<>std::get<>当参数是右值返回xvalues

标准的引用也很好!

c++ rvalue copy-elision c++17 structured-bindings

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

C ++ 17中不可复制变量的成员初始化

在对不可复制变量(例如std::atomic<int>)执行成员初始化时,需要使用direct-initialization而不是copy-initialization根据此处的答案。然而,当我打开-std=c++17g++ 7.4.0,似乎后者也是行之有效的。

#include <atomic>

class A {
    std::atomic<int> a = 0;     // copy-initialization
    std::atomic<int> b{0};      // direct-initialization
};
Run Code Online (Sandbox Code Playgroud)
$ g++ -c atomic.cc -std=c++11    // or c++14
atomic.cc:4:26: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
     std::atomic<int> a = 0;     // copy-initialization

$ g++ -c atomic.cc -std=c++17
// no error
Run Code Online (Sandbox Code Playgroud)

与编译时,它也没有g++ 6.5.0,甚至有-std=c++17。这里哪一个是正确的?

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

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

构造函数初始化列表不是调用复制构造函数

所以我学习了构造函数初始化列表,并编写了以下代码:

class Mango
{
  public:

  Mango(){cout<<"Mango::ctor()";}
  Mango(const Mango& other){cout<<"Mango::copy_ctor()";}
};

class Box
{
    public:

    Box() : mango(Mango()) //**doesn't call copy constructor**
    {
    }

    Mango mango;
};

int main()
{
  Box box; 

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

我为此使用了g ++编译器.它调用构造函数而不是复制构造函数.它应该调用复制构造函数,因为我正在创建一个对象来创建另一个对象?这里有什么问题,标准说了什么?

c++ constructor initialization language-lawyer copy-elision

15
推荐指数
1
解决办法
756
查看次数

编译器是否可以删除以下副本?

我仍然是一名新手程序员,我知道过早的优化很糟糕,但我也知道复制大量的东西也很糟糕.

我已经阅读了复制省略和它的同义词,但维基百科上的例子让我觉得复制省略只有在要完全构建的同时返回要返回的对象时才会发生.

那些像矢量这样的对象呢?当用作返回值时,它通常只在填充某些东西时才有意义.毕竟,可以手动实例化空矢量.

那么,它是否也适用于这样的情况?

简洁的风格:

vector<foo> bar(string baz)
{
    vector<foo> out;
    for (each letter in baz)
        out.push_back(someTable[letter]);

    return out;
}

int main()
{
     vector<foo> oof = bar("Hello World");
}
Run Code Online (Sandbox Code Playgroud)

我使用bar(矢量和输出,字符串文本)没有真正的麻烦,但上面的方式看起来更好,美观,并且意图.

c++ copy-elision

14
推荐指数
3
解决办法
990
查看次数

移动构造函数在下面显示的代码段中是否有任何特殊原因?

抛出对象后,gcc,clang和VS2015不会在下面的代码中忽略对move构造函数的调用a.在我看来,满足§8.12[class.copy]/31(N4140)的项目符号(31.2)中确定的条件.

#include <iostream>

struct A
{
    A() { std::cout << "Default ctor " << '\n'; }
    A(const A& a) { std::cout << "Copy ctor" << '\n'; }
    A(A&& a) { std::cout << "Move ctor" << '\n'; }
    ~A() { std::cout << "Destructor " << '\n'; }
};

int main()
{
    try
    {
        A a;
        throw a;
    }
    catch(A& a) { std::cout << "Caught" << '\n'; }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这a是一个左值,但根据§12.8/ 32,首先执行重载决策以选择副本的构造函数,就像对象由rvalue指定一样.也就是说,对move构造函数的调用是可以的.如果删除上面的移动构造函数的定义,则调用复制构造函数,但同样,它不会被省略!

我理解标准没有规定复制省略,但我很想知道是否有任何特殊条件可以证明这一事实,上面提到的三个编译器在这个特定的例子中避免了这种优化.

gcc的示例输出,来自上面的链接:

g ++ -std …

c++ exception copy-elision c++14

14
推荐指数
1
解决办法
256
查看次数

在C++ 14允许的情况下,C++ 17是否禁止复制省略?

考虑以下:

struct X {
    X() {}
    X(X&&) { puts("move"); }
};
X x = X();
Run Code Online (Sandbox Code Playgroud)

在C++ 14中,尽管移动构造函数由于[class.copy]/31而具有副作用,但移动可能会被省略,

在下列情况下允许复制/移动操作的省略...当未绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv-nonqualified的类对象时类型

在C++ 17中,这个子弹被删除了.相反,由于[dcl.init] /17.6.1,保证可以省略此举:

如果初始化表达式是prvalue且源类型的cv-nonqualified版本与目标类相同,则初始化表达式用于初始化目标对象.[ 示例: T x = T(T(T()));调用T默认构造函数进行初始化x.- 结束例子 ]

到目前为止,我所陈述的事实众所周知.但现在让我们更改代码,使其显示为:

X x({});
Run Code Online (Sandbox Code Playgroud)

在C++ 14中,执行重载解析并使用默认构造函数将其{}转换为临时类型X,然后移入x.复制省略规则允许省略此移动.

在C++ 17中,重载决策是相同的,但现在[dcl.init] /17.6.1不适用,并且C++ 14中的子弹不再存在.没有初始化表达式,因为初始化程序是braced-init-list.相反,似乎[dcl.init] /(17.6.2)适用:

否则,如果初始化是直接初始化,或者如果它是复制初始化,其中源类型的cv-nonqualified版本与目标类相同的类或派生类,则考虑构造函数.列举了适用的构造函数(16.3.1.3),并通过重载解析(16.3)选择最佳构造函数.调用所选的构造函数来初始化对象,初始化表达式或表达式列表作为其参数.如果没有构造函数适用,或者重载决策是不明确的,则初始化是错误的.

这似乎需要调用移动构造函数,如果标准中的其他地方有一条规则说可以忽略它,我不知道它在哪里.

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

12
推荐指数
1
解决办法
439
查看次数

理解c ++ 11 rvalues,移动语义和性能

可能重复:
如果我返回文字而不是声明std :: string会发生什么?

请考虑以下代码

string getName () {
    return "meme";
}

string name = getName();
Run Code Online (Sandbox Code Playgroud)

函数getName()返回一个临时对象.在c ++ 03中,我理解调用"string"的复制构造函数并销毁临时对象.实际上似乎编译器(至少在gcc 4.7中)通过不创建对象"name"来优化第5行,而是将其替换为临时对象本身而不是破坏临时对象(我尝试使用MyVector类;而不是std :: string).

如C++ 11标准中所定义,
1.getName()是否返回rvalue?
2.在上面第5行中,字符串的构造函数被调用(移动还是复制)?我是否必须调用std :: move()来调用移动构造函数?
3.使用移动语义,它是否比编译器提供的"复制省略"优化效率低?

c++ move-semantics return-value-optimization copy-elision c++11

11
推荐指数
1
解决办法
500
查看次数

按值传递导致额外移动

我试图理解移动语义和复制/移动省略.

我想要一个包含一些数据的类.我想在构造函数中传递数据,我想拥有数据.

看完这个,这个这个给我的感觉是,在C++ 11,如果我想保存一个副本,然后从增加的代码大小的小问题,通过按值应至少与任何其他的选择,因为有效的(除).

然后,如果调用代码想要避免复制,则可以通过传递右值而不是左值.(例如使用std :: move)

所以我试了一下:

#include <iostream>

struct Data {
  Data()                 { std::cout << "  constructor\n";}
  Data(const Data& data) { std::cout << "  copy constructor\n";} 
  Data(Data&& data)      { std::cout << "  move constructor\n";}
};

struct DataWrapperWithMove {
  Data data_;
  DataWrapperWithMove(Data&& data) : data_(std::move(data)) { }
};

struct DataWrapperByValue {
  Data data_;
  DataWrapperByValue(Data data) : data_(std::move(data)) { }
};

Data
function_returning_data() {
  Data d;
  return d;
}

int main() {
  std::cout << …
Run Code Online (Sandbox Code Playgroud)

c++ move-semantics copy-elision c++11

11
推荐指数
1
解决办法
454
查看次数

返回不可复制常量值的函数的不直观 RVO?

考虑以下 C++ >=17 中的示例代码:

struct A{
    A() = default;
    A(const A&) = delete;
};

const A f(){ return A{}; }

int main(){
    const A& a = f(); // OK
    // A& b = f();    // Error: cannot convert 'const A' to 'A&'
    const A c = f();  // OK: Copy elision
    A d = f();        // OK!?
}
Run Code Online (Sandbox Code Playgroud)

该类A是不可复制的,但由于强制复制省略,我们可以将 的结果f()放入变量中。根据cppreference.com 中的这个页面,上述行为是完全合法的,因为它指定const在发生复制省略时忽略返回值上的量词。

然而,这种行为对我来说似乎非常违反直觉。由于A是不可复制的,我觉得应该没有办法const A变成A(除非你有A::A(const …

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

11
推荐指数
1
解决办法
187
查看次数