【问题标题】:Why is copy constructor called even when parameter is marked 'const'?即使参数标记为“const”,为什么还要调用复制构造函数?
【发布时间】:2019-12-05 15:04:01
【问题描述】:

考虑以下两个函数:

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 更改,因此编译器应该仍然能够像调用 foo2(a) 一样直接传递 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&)

我猜答案与constfoo 的定义中被删除这一事实有关,但我不知道为什么。抱歉,如果我遗漏了一些明显的东西。

谢谢!

【问题讨论】:

  • 不,它不能,你通过值传递它它必须复制
  • Const or no const,你还是按值传递,所以这里编译器不做这个优化也没有错。如果你足够疯狂地传递 (const) 值然后将 const 去掉怎么办?无论如何,为什么要这样做并指望编译器为您优化呢?为什么不像第二个例子那样直接通过 ref 传递?

标签: c++ parameter-passing constants pass-by-reference copy-constructor


【解决方案1】:

对于非引用参数,const 在编译器存储函数签名时实际上被忽略了。例如,给定这个函数原型:

void func(std::string);

func可以用这个签名实现:

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

所以const 对值参数的传递方式没有任何影响。它们被复制。 const 仅影响参数在函数实现中的使用方式。

【讨论】:

    【解决方案2】:

    编译器不优化它是正确的。你可以做类似的事情

    #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;
    }
    

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-26
        • 1970-01-01
        • 2012-09-15
        • 1970-01-01
        • 1970-01-01
        • 2021-05-14
        • 2013-11-23
        • 2013-12-25
        相关资源
        最近更新 更多