English 中文(简体)
编译器能删掉下面的副本吗?
原标题:Can the compiler elide the following copy?

我还是一个新手程序员,我知道过早的优化是不好的,但我也知道复制大量的东西也是不好的。

我读过关于复制省略和它的同义词,但例如维基百科上的例子让我觉得,只有当要返回的对象在完全构建的同时返回时,复制省略才能发生。

What about objects like vectors, which usually only make sense when filled with something, when used as a return value. After all, an empty vector could just be instantiated manually.

那么,它在这种情况下也有效吗?

简洁风格不好:

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");
}

我使用bar(vector&;out,字符串文本)并没有真正的问题,但上面的方式看起来会更好,美观,而且符合目的。

最佳回答

例如,维基百科上的例子让我觉得,只有当要返回的对象在完全构建的同时返回时,才能进行复制省略。

这是误导(读作:错误)。问题是,在所有代码路径中只有一个对象被返回,即潜在返回对象只有一个构造正在发生。

你的代码很好,任何现代编译器都可以删除副本。

另一方面,以下代码可能会产生问题:

vector<int> foo() {
    vector<int> a;
    vector<int> b;
    // … fill both.
    bool c;
    std::cin >> c;
    if (c) return a; else return b;
}

在这里,编译器需要完全构造两个不同的对象,只有之后才能决定返回其中的哪一个,因此它必须复制一次,因为它无法在目标内存位置直接构造返回的对象。

问题回答

没有什么可以阻止编译器删除副本。其定义见12.8.15:

[…] This elision of copy operations is permitted in the following circumstances (which may be combined to eliminate multiple copies):

[…]

  • when a temporary class object that has not been bound to a reference (12.2) would be copied to a class object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy

它是否真的这样做取决于编译器和您使用的设置。

向量的两个隐含副本都可以而且经常被消除。命名返回值优化可以消除return语句<code>return out中隐含的副本的复制初始化中隐含的for the temporary也可以被消除。

在两种优化都在进行的情况下,在<code>vector<;foo>;out是与oof相同的对象。

使用这样的人工测试用例来测试这些优化中的哪一个更容易。

struct CopyMe
{
    CopyMe();
    CopyMe(const CopyMe& x);
    CopyMe& operator=(const CopyMe& x);

    char data[1024]; // give it some bulk
};

void Mutate(CopyMe&);

CopyMe fn()
{
    CopyMe x;
    Mutate(x);
    return x;
}

int main()
{
    CopyMe y = fn();
    return 0;
}

复制构造函数已声明但未定义,因此无法内联和消除对它的调用。使用现在相对较旧的gcc 4.4编译时,会在-O3-fno-inline中生成以下程序集(经过过滤以分解C++名称,并经过编辑以删除非代码)。

fn():
        pushq   %rbx
        movq    %rdi, %rbx
        call    CopyMe::CopyMe()
        movq    %rbx, %rdi
        call    Mutate(CopyMe&)
        movq    %rbx, %rax
        popq    %rbx
        ret

main:
        subq    $1032, %rsp
        movq    %rsp, %rdi
        call    fn()
        xorl    %eax, %eax
        addq    $1032, %rsp
        ret

可以看出,没有对复制构造函数的调用。事实上,gcc甚至在-O0时也会执行这些优化。您必须提供-fno-elide构造函数才能关闭此行为;如果这样做,那么gcc会生成两个对<code>CopyMe</code>的复制构造函数的调用——一个在对<code<fn()</code<的调用内部,一个在调用外部。

fn():
        movq    %rbx, -16(%rsp)
        movq    %rbp, -8(%rsp)
        subq    $1048, %rsp
        movq    %rdi, %rbx
        movq    %rsp, %rdi
        call    CopyMe::CopyMe()
        movq    %rsp, %rdi
        call    Mutate(CopyMe&)
        movq    %rsp, %rsi
        movq    %rbx, %rdi
        call    CopyMe::CopyMe(CopyMe const&)
        movq    %rbx, %rax
        movq    1040(%rsp), %rbp
        movq    1032(%rsp), %rbx
        addq    $1048, %rsp
        ret

main:
        pushq   %rbx
        subq    $2048, %rsp
        movq    %rsp, %rdi
        call    fn()
        leaq    1024(%rsp), %rdi
        movq    %rsp, %rsi
        call    CopyMe::CopyMe(CopyMe const&)
        xorl    %eax, %eax
        addq    $2048, %rsp
        popq    %rbx
        ret




相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签