标签: copy-elision

为什么自动移动不能与从右值引用输入返回值的函数一起使用?

我已经知道自动移动不会与从右值参考输入返回值的函数一起唤醒。但为什么?

下面是自动移动不起作用的示例代码。

Widget makeWidget(Widget&& w) {
  ....
  return w; // Compiler copies w. not move it.
}
Run Code Online (Sandbox Code Playgroud)

如果函数输入来自按值复制,则自动移动有效。

Widget makeWidget(Widget w) {
  ....
  return w; // Compiler moves w. not copy it.
}
Run Code Online (Sandbox Code Playgroud)

c++ copy-elision

2
推荐指数
1
解决办法
188
查看次数

为什么使用 C++17 禁用 std::atomic 的复制省略不起作用?

由于std::atomic复制构造函数被删除,并且由于复制省略,这应该只能使用 C++17 及更高版本进行编译:

std::atomic<int> t_int = 1; 
Run Code Online (Sandbox Code Playgroud)

我预计它不会使用-fno-elide-constructors标志进行编译,但它仍然可以编译:

https://godbolt.org/z/nMvG5vTrK

为什么是这样?

c++ copy-elision c++17

2
推荐指数
1
解决办法
158
查看次数

C++ 按值返回类对象优化后的内存行踪

假设有一个用户定义的class Foo。一些帖子表明 C++ 类对象“永远”不会在堆上分配,除非使用new. 但!另一方面,有一些帖子建议从函数中按值返回本地外观的类对象不一定会复制任何数据。所以!这样一个对象的数据首先存储在哪里?还在堆吗?它是否被提升到调用函数的堆栈帧?

class Foo {
...
}

Foo a(int x) {
  Foo result;
  doabc(x, result);
  return result;
}

Foo b(int x) {
  Foo result = a(x);
  doxyz(x,result);
  return result;
}

int main() {
    int x;
    cin >> x;
    Foo result = b(x);
    dosomethingelse(result);
    cout << result;
}
Run Code Online (Sandbox Code Playgroud)

如果 a 的 Foo 结果不是按值复制的,那么它在哪里分配?堆还是栈?如果在堆上,编译器是否会自动重构代码以插入删除?如果在堆栈上,它会驻留在哪个堆栈帧上?b 的?这是让我想知道的帖子:/sf/answers/1223171211/。谢谢!

c++ stack-frame return-value-optimization copy-elision

2
推荐指数
1
解决办法
79
查看次数

如何为特征向量启用复制删除移动成员?

2011年,该补丁中提交了Eigen移动支持.但是我在Matrix头文件中找不到移动构造函数.此外,Eigen网页仍然将移动语义列为"待办事项".所有这些表明补丁尚未提交到发布版本

此测试程序证明移动构造函数保持移动的对象不变.

#include <iostream>
#include <utility>

#include <eigen3/Eigen/Dense>

int main()
{
    Eigen::VectorXd first = Eigen::VectorXd::Constant(3, 3.14);
    std::cout << "first\n" << first << std::endl << std::endl;
    Eigen::VectorXd other = std::move(first);
    std::cout << "first\n" << first << std::endl << std::endl;
    std::cout << "other\n" << other << std::endl << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

first
3.14
3.14
3.14

first
3.14
3.14
3.14

other
3.14
3.14
3.14
Run Code Online (Sandbox Code Playgroud)

如何从Eigen 3.2.0中的上述补丁中启用复制删除移动功能.

编辑:

似乎特征类的移动语义没有任何问题.但是,只有 …

c++ move eigen copy-elision c++11

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

如何使用C++ 11移动语义从函数返回std :: vector?

我知道C++ 11从这个链接中移动了语义: 现代C++ Style的元素

但它没有介绍如何使用移动语义返回向量.这该怎么做?

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

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

如何让"工厂功能"返回不可复制的对象?

上下文

尝试使用不同的文件名创建一些gzip存档我写下以下代码片段.

#include <iostream>
#include <utility>

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/gzip.hpp>

boost::iostreams::filtering_ostream&& makeGZipStream(const std::string& archiveName,
                                                     const std::string& fileName)
{
    boost::iostreams::filtering_ostream theGzipStream;

    boost::iostreams::gzip_params theGzipParams;

    theGzipParams.file_name = fileName;

    theGzipStream.push(boost::iostreams::gzip_compressor{theGzipParams});

    theGzipStream.push(boost::iostreams::file_sink{archiveName});

    return std::move(theGzipStream);
}

int main()
{
    boost::iostreams::filtering_ostream&& theGzipStream = makeGZipStream("archive.gz", "file");

    theGzipStream << "This is a test..." << std::endl;

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

问题

这(我们可以预期)会产生核心转储,因为makeGZipStream我们尝试通过(rvalue-)引用返回本地堆栈分配的变量.但在这种情况下,副本不是一个选项,因为它boost::iostreams::filtering_ostream是不可复制的.

问题

  1. 由于它的移动构造函数,我们可以返回std::unique_ptr"按值"(由于copy-elision,这个移动甚至不应该出现在C++ 17中),为什么在这种情况下不可能呢?
  2. 有什么好的解决方案?

可能的解决方案

  1. 将所有内容放在相同的范围内(我试图避免的)
  2. 将你的物体包裹在一个unique_ptr(不那么漂亮)
  3. 还要别的吗 ?

笔记

使用的编译器很老了g++ (GCC) 4.9.3.

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

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

移动构造函数与复制省略

有人可以向我解释一件事吗?从一方面来看,它的move constructor设计目的是通过消除不必要的复制对象来优化内存和处理器的使用,但从另一面来看,几乎所有地方move constructor都会使用编译器使用复制省略move ctor,禁用?的使用。这不是不合理吗?

c++ constructor move-semantics copy-elision

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

我可以在返回多个值时避免复制,同时保留我的返回类型吗?

如果我们写如下函数:

auto foo() {
    Foo foo { /* ... */ };
    do_stuff(foo);
    return foo;
}
Run Code Online (Sandbox Code Playgroud)

然后NRVO应该启动,这样foo就不会在返回时被复制。

现在假设我想返回两个不同的值:

auto foo() {
    Foo foo { /* ... */ };
    Bar bar { /* ... */ };
    do_stuff(foo, bar);
    return std::make_tuple(foo, bar);
}
Run Code Online (Sandbox Code Playgroud)

这种幼稚的实现可能会触发构建每个FooBar( GodBolt)的两个副本。

我应该如何最好地修改我的代码以避免这种复制,而不会弄乱我的返回类型?

c++ move-semantics copy-elision nrvo stdmove

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

三元运算符中是否强制复制省略(如果允许的话)?

请考虑以下 C++17 代码:

#include <iostream>
#include <optional>

struct S
{
    S(int) { std::cout << "S() "; }
    S(const S &) { std::cout << "S(const S &) "; }
    S(S &&) = delete;
    ~S() { std::cout << "~S() "; }
};

int main() 
{
    [[maybe_unused]] std::optional<S> v = true ? std::optional<S>(1) : std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)

在带有 /std:c++latest 选项 (C++20) 的最新 Visual Studio 2019 16.10.3 中,它会打印

S() S(const S &) ~S() ~S()
Run Code Online (Sandbox Code Playgroud)

即使在具有优化的发布配置中。

即使没有优化,GCC 和 Clang 输出也是不同的(https://gcc.godbolt.org/z/ofGrzhjbc

S() ~S()
Run Code Online (Sandbox Code Playgroud)

复制省略在这里是可选的(所有编译器都在他们的权利范围内),还是这里不允许复制省略(只有 MSVC …

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

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

即使使用-fno-elide-constructors进行编译,似乎也会出现复制省略

#include <iostream>

class A {
public:
    A() { std::cout << "Constructor" << std::endl; }
    A(const A& a) { std::cout << "Copy Constructor" << std::endl; }
    A& operator=(const A& a) { std::cout << "Copy = operator" << std::endl; }
    A(A&& a) { std::cout << "Move Constructor" << std::endl; }
    A& operator=(A&& a) { std::cout << "Move = operator" << std::endl; }
    ~A() { std::cout << "Destructor" << std::endl; }
};

void f(A&& a) { std::cout << "function" << std::endl; }

int …
Run Code Online (Sandbox Code Playgroud)

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

0
推荐指数
1
解决办法
113
查看次数

C++17 中的聚合初始化可以执行复制省略吗?

鉴于:

//C++17
#include <string>
struct Foo {
    int i;
    std::string str;
};

int main() {
    Foo foo{1, std::string("Hello, world!")};
}
Run Code Online (Sandbox Code Playgroud)

可以Foo::i直接Foo::str1std::string(...)初始化,而不是复制到其中,并解释为什么可以/不能使用 C++17 标准(可能是一些用于测试目的的代码)?

如果不能,需要多少份?

c++ aggregate-initialization copy-elision c++17

0
推荐指数
1
解决办法
292
查看次数

为什么复制省略是 as-if 规则的例外?

为什么标准允许我的编译器应用复制省略,即使它涉及可见的副作用,从而打破了 as-if 规则?

当一个人保证复制省略时,这对我来说是有道理的,因为复制/移动的实际功能(这将调用程序行为的可见变化)不一定存在,但为什么/如何在 C+ 之前+17?

是不是因为编译器一般不能检测副作用(不知道是否可行)?

c++ copy-elision as-if

0
推荐指数
1
解决办法
144
查看次数

创建新的类对象并移动语义

有这个简单的类:

#include <iostream>

class B 
{ 
public:  
    //default constructor
    B(const char* str = "\0") {
        std::cout << "Constructor called\n";
    }

    //copy constructor
    B(const B& b)   {
        std::cout << "Copy constructor called\n";
    }

    //move constructor
    B(B&& b) {
        std::cout << "Move constructor called\n";
    }
}; 
Run Code Online (Sandbox Code Playgroud)

这些语句之间在移动语义方面有什么区别:

B o1 = B("abc");
B o2 = B(B("abc")); 
Run Code Online (Sandbox Code Playgroud)

这两行等价吗?

c++ constructor move-semantics copy-elision

0
推荐指数
1
解决办法
98
查看次数