即使参数标记为“const”,为什么复制构造函数还会被调用?

3

考虑以下两个函数:

int foo(const std::string x) {
    return x.length();
}

int foo2(const std::string& x2) {
    return x2.length();
}

当调用时

std::string a("hello world!");
foo(a);

编译器似乎仍会将临时对象(通过复制构造函数创建)传递给foohttps://godbolt.org/z/p2ID1d)。为什么会这样?因为x是const的,因此不会被foo更改,因此编译器应该仍然能够直接传递a,就像调用foo2(a)时一样。顺便提一下:我正在查看godbolt生成的函数类型:
foo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)

foo2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)

我猜这个问题与 const 在定义函数 foo 时被删除有关,但我不知道为什么。如果我漏掉了什么显而易见的东西,对不起。
谢谢!

3
不行,你正在按值传递它,它必须进行复制。 - Borgleader
1
无论是否使用const,您仍然是按值传递,因此编译器不会在这里进行优化。如果您疯狂到通过(const)值传递,然后取消const怎么办?反正,为什么要这样做并依靠编译器为您进行优化呢?为什么不像第二个示例一样通过引用传递呢? - Boris Lipschitz
3个回答

3
对于非引用参数,在编译器存储函数签名时,实际上会忽略const关键字。例如,给定以下函数原型:
void func(std::string);

func 可以使用这个签名来实现:

void func(const std::string) // This is NOT an overload.
{}

所以const对值参数的传递没有任何影响。它们是被复制的。 const只对函数实现中参数的使用产生影响。


1
编译器不优化它是正确的。你可以尝试像这样做:
#include <iostream>
#include <thread>


void foo(const std::string x) {
    using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s);
    std::cout << x.length() << '\n';
}

int foo2(const std::string& x2) {
    using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s);
    std::cout << x2.length() << '\n';
}

int main() {
    std::string a("hello world!");
    std::thread t1([&]{
        foo(a);
    });
    std::thread t2([&]{
        foo2(a);
    });
    a = "";
    t1.join();
    t2.join();
    return 0;
}

这甚至可以在后台发生,编译器也不会知道。

0

当你通过值传递时,编译器必须创建一个副本。

通过const值传递的效果仅仅是你的函数不允许修改它接收到的副本。与通过const &传递相比,这样做没有任何好处 - 相反,它更低效,因为它涉及到复制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接