标签: copy-elision

是否有可能确保复制省略?

复制省略是一种简洁的优化技术,在某些情况下,依赖复制省略实际上比"手动"传递参考更快.

因此,我们假设您已经确定了一个关键代码路径,您依赖于编译器为代码路径执行复制省略以获得最佳性能的事实.

但现在您依赖于编译器优化.

是否有任何(编译器特定的,显然)方式确保实际执行复制省略并且如果无法执行复制省略,编译器(或其他工具)会生成警告/错误?

(我正在考虑远远类似于Visual C++的东西,__forceinline如果标记的函数没有被编译器内联,则会产生警告.)

c++ diagnostics compiler-directives copy-elision

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

传递重物C++ 0x

我有一个函数,它产生一种昂贵的对象(包含向量和非固定大小的映射),所以我真的想避免调用copy c'tors.

到目前为止,我刚刚从方法中返回了一个std :: shared_ptr并使用了它,但我觉得它很难看,并且需要使用typedeffing才能真正使用它.

我知道有两件事可以帮助我.首先复制elision,第二个是移动语义.

我的问题是我知道如何正确使用.我的研究告诉我,复制省略完全由编译器完成,并不是st'd的一部分.我真的不想完全依赖于此.

那么我如何确保调用移动分配并确保它已到位以防止编译器复制elision.

ResultSet &&generateResults()
{
    //ResultSet a(); :S
    ResultSet a;
    a.populat(...
    //blah blah blah
    return a;
}

//else where (where the && assignment operator is overloaded
ResultsSet b = generateResults();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这是最正确的编码方式吗?如果不是,我怎么能改进它.我很高兴使用C++ 0x only构造.

BTW:我的编译器是gcc 4.6

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

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

vector.push_back rvalue和copy-elision

push_back是一个vector像这样的临时对象,

vector<A> vec;
vec.push_back(A("abc"));
Run Code Online (Sandbox Code Playgroud)

将编译器应用copy-elision A("abc")直接构造临时vector,以便A在将临时对象推入时不会触发copy ctor vec.

c++ vector copy-elision

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

通过Value和复制省略优化

我发现了这篇文章http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

作者的建议:

不要复制函数参数.相反,按值传递它们,让编译器进行复制.

但是,我在文章中提到的两个示例中没有获得什么好处:

//Don't
    T& T::operator=(T const& x) // x is a reference to the source
    { 
        T tmp(x);          // copy construction of tmp does the hard work
        swap(*this, tmp);  // trade our resources for tmp's
        return *this;      // our (old) resources get destroyed with tmp 
    }
Run Code Online (Sandbox Code Playgroud)

VS

// DO
    T& operator=(T x)    // x is a copy of the source; hard work already done
    {
        swap(*this, x);  // trade our resources for x's
        return *this;    // our …
Run Code Online (Sandbox Code Playgroud)

c++ compiler-optimization copy-elision

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

复制Elision误解

#include <iostream>

struct A
{
    A() { std::cout << "Def Constr\n"; }

    A(const A&) { std::cout << "Copy Constr\n"; }
};

A func1() 
{
    return A{};
}

void func2(A a) {}

int main()
{
    func2(func1());
}
Run Code Online (Sandbox Code Playgroud)

编译完成后

g ++ Copy.cpp -std = c ++ 11 -fno-elide-constructors

输出是:

Def Constr

复制Constr

复制Constr

我的问题是:为什么2复制Constr?我以为只需要1份复印件.

我可能猜测func1()会抛出一个临时对象,并且需要将此临时对象复制到另一个内存区域,并且必须再次从该区域为func2()参数创建一个副本,但它对我来说是模糊的.

你能详细解释一下吗?

c++ copy-elision c++11

7
推荐指数
2
解决办法
201
查看次数

从函数返回本地值而不触发复制构造函数

我试图使用c ++类型系统删除复制构造函数,以防止复制对象.

struct DeleteCopyConstructor {
    DeleteCopyConstructor() {};
    DeleteCopyConstructor(DeleteCopyConstructor& op2) = delete;
    DeleteCopyConstructor(const DeleteCopyConstructor& op2) = delete;
};

DeleteCopyConstructor f() {
    DeleteCopyConstructor d;
    // initialize d...
    return d;
}
Run Code Online (Sandbox Code Playgroud)

错误是:

error: use of deleted function ‘DeleteCopyConstructor::DeleteCopyConstructor(const DeleteCopyConstructor&)’
Run Code Online (Sandbox Code Playgroud)

我读过有关复制省略,但它似乎是一个编译器优化,所以我认为它不适用.如何在d不触发复制构造的情况下返回?

c++ oop class copy-constructor copy-elision

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

在无法完成RVO的情况下,我们应该写`std :: move`吗?

众所周知,std::move不应该将其应用于函数返回值,因为它可以阻止RVO(返回值优化).我感兴趣的是,如果我们确实知道RVO不会发生,我们应该怎么做.

这就是C++ 14标准所说的[12.8/32]

当满足复制/移动操作的省略标准时,但不满足异常声明,并且要复制的对象由左值指定,或者当返回语句中的表达式是(可能带有括号的)id-时表达式,用于在最内层封闭函数或lambda-expression的body或parameter-declaration-clause中声明的具有自动存储持续时间的对象,首先执行重载决策以选择复制的构造函数,就像对象由rvalue指定一样.如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值.[注意:无论是否发生复制省略,都必须执行此两阶段重载决策.如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数. - 结束说明]

这是本书的解释 Effective Modern C++

标准祝福RVO的部分接着说,如果满足RVO的条件,但编译器选择不执行复制省略,则返回的对象必须被视为右值.实际上,标准要求在允许RVO时,发生复制省略或将std :: move隐式应用于返回的本地对象

据我所知,当返回物体最初不能被省略时,它应被视为rvalue.在这些例子中,我们可以看到,当我们传递大于5object的参数时,否则会被复制.std::move当我们知道RVO不会发生时,这是否意味着我们应该明确写出来?

#include <iostream>
#include <string>


struct Test
{
    Test() {}

    Test(const Test& other)
    {
        std::cout << "Test(const Test&)" << std::endl;
    }

    Test(Test&& other)
    {
        std::cout << "Test(const Test&&)" << std::endl;
    }
};

Test foo(int param)
{
    Test test1;
    Test test2;
    return param > 5 ? std::move(test1) : test2;
}

int main()
{
    Test res = foo(2);
}
Run Code Online (Sandbox Code Playgroud)

这个程序的输出是Test(const …

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

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

复制初始化列表中的构造

我在探索丑陋的世界std::intializer_list.

据我所知,从标准:

§11.6.4:

  1. std :: initializer_list类型的对象是从初始化列表构造的,就好像实现生成并实现了(7.4)类型为"const const E"的prvalue,其中N是初始化列表中的元素数.使用初始化列表的相应元素对该数组的每个元素进行复制初始化,并构造std :: initializer_list对象以引用该数组.[注意: 在初始化列表的上下文中,可以访问为副本选择的构造函数或转换函数(第14条). - 尾注] [...]

因此,如果类型E是一个,我希望调用复制构造函数.


以下类不允许复制构造:

struct NonCopyable {
  NonCopyable() = default;   
  NonCopyable(const NonCopyable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

我将尝试std::initializer_list使用此类实例化一个.

#include <vector>

void foo() {
  std::vector<NonCopyable>{NonCopyable{}, NonCopyable{}};
}
Run Code Online (Sandbox Code Playgroud)

随着g++-8.2 -std=c++14我得到我期望的,编译器错误:

error: use of deleted function 'NonCopyable::NonCopyable(const NonCopyable&)'.

完善!


但是,行为随新标准而变化.

的确,g++-8.2 -std=c++17编译.

编译器资源管理器测试


我认为这是因为copy elision新标准提出的新要求,起初.

但是,更改标准库实现 …

c++ initializer-list copy-elision c++17

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

使用 co_await 时,不可复制和不可移动类型上出现意外的 memcpy

前言

这是我尝试使用代码执行的操作的描述,请跳到下一部分以查看实际问题。

我想在嵌入式系统中使用协程,但我无法承受太多的动态分配。因此,我正在尝试以下操作:对于对外围设备的各种查询,我有不可复制、不可移动的可等待类型。查询外围设备时,我使用类似auto result = co_await Awaitable{params}. 可等待的构造函数准备对外围设备的请求,注册其内部buffer以接收回复,并ready在承诺中注册其标志。然后协程被挂起。

稍后,buffer将被填充,并且ready标志将被设置为true。此后,协程知道它可以恢复,这会导致等待对象在被销毁之前从缓冲区复制出结果。

可等待的内容是不可复制且不可移动的,以强制在任何地方进行有保证的复制省略,这样我就可以确保指向bufferready保持有效的指针,直到等待可等待的内容为止(至少这是计划......)

问题

我在以下代码中遇到 ARM GCC 11.3 的问题:

#include <cstring>
#include <coroutine>

struct AwaitableBase {
    AwaitableBase() = default;
    AwaitableBase(const AwaitableBase&) = delete;
    AwaitableBase(AwaitableBase&&) = delete;

    AwaitableBase& operator=(const AwaitableBase&) = delete;
    AwaitableBase& operator=(AwaitableBase&&) = delete;

    
    char buffer[65];
};

struct task {
    struct promise_type
        {
            bool* ready_ptr;

            task get_return_object() { return {}; }
            std::suspend_never initial_suspend() noexcept { return …
Run Code Online (Sandbox Code Playgroud)

c++ undefined-behavior copy-elision c++-coroutine

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

函数参数按值传递比按引用传递更快?

我接受了一次采访,得到了以下函数声明:

int f1(const std::vector<int> vec)
Run Code Online (Sandbox Code Playgroud)

我建议我们不要复制向量,而应该使用 const 引用(更不用说 const 复制没有多大意义),但面试官声称编译器复制省略会处理它。我当场想不出什么强有力的论据,但今天我做了一些研究。

我实现了以下两个简单的示例函数:

int f1(const std::vector<int> vec) {
    const auto num = vec.size();
    return num * num;
}


int f2(const std::vector<int>& vec) {
    const auto num = vec.size();
    return num * num;
}
Run Code Online (Sandbox Code Playgroud)

godbolt汇编中可以清楚地看出,该f2函数有 2 条附加指令,因此它应该更慢。(我认为 2mov在现代 CPU 中技术上几乎是免费的)

我还使用quick-bench来测量这两个解决方案,但它证实了我的怀疑,通过const-ref更快。(即使对于 1 个元素)

在此输入图像描述

我怀疑可能因为 的原因而不允许复制省略benchmark::DoNotOptimize(result);,但删除它后,我收到了类似的结果。

现在我有了这些结果,但我觉得还是不够有说服力。

你怎么认为?

对于使用其中一种而不是另一种,您有什么好的理由吗?

c++ optimization copy-elision

6
推荐指数
2
解决办法
346
查看次数