为什么即使参数标记为 'const' 也会调用复制构造函数?
Why is copy constructor called even when parameter is marked 'const'?
考虑以下两个函数:
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);
编译器似乎仍然将临时对象(通过复制构造函数创建)传递给 foo
( https://godbolt.org/z/p2ID1d )
为什么要这样做? x 是 const,因此它不会被 foo
更改,因此编译器应该仍然能够直接传递 a
,就像调用 foo2(a)
.[=21= 一样]
旁注:我正在查看由 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
的定义中被删除这一事实有关,但我不知道为什么。对不起,如果我遗漏了一些明显的东西。
谢谢!
按值传递时,编译器必须创建一个副本。
传递const
值的效果只是不允许您的函数修改它接收到的副本。通过 const &
执行此操作没有任何好处 - 相反,它的效率较低,因为它涉及副本。
编译器不优化是对的。你可以做类似
的事情
#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;
}
这甚至可以在后台发生,编译器不会知道。
对于非引用参数,编译器存储函数签名时实际上会忽略const
。例如,给出这个函数原型:
void func(std::string);
func
可以用这个签名实现:
void func(const std::string) // This is NOT an overload.
{}
所以 const
对值参数的传递方式没有任何影响。它们被复制。 const
仅影响参数在函数实现中的使用方式。
考虑以下两个函数:
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);
编译器似乎仍然将临时对象(通过复制构造函数创建)传递给 foo
( https://godbolt.org/z/p2ID1d )
为什么要这样做? x 是 const,因此它不会被 foo
更改,因此编译器应该仍然能够直接传递 a
,就像调用 foo2(a)
.[=21= 一样]
旁注:我正在查看由 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
的定义中被删除这一事实有关,但我不知道为什么。对不起,如果我遗漏了一些明显的东西。
谢谢!
按值传递时,编译器必须创建一个副本。
传递const
值的效果只是不允许您的函数修改它接收到的副本。通过 const &
执行此操作没有任何好处 - 相反,它的效率较低,因为它涉及副本。
编译器不优化是对的。你可以做类似
的事情#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;
}
这甚至可以在后台发生,编译器不会知道。
对于非引用参数,编译器存储函数签名时实际上会忽略const
。例如,给出这个函数原型:
void func(std::string);
func
可以用这个签名实现:
void func(const std::string) // This is NOT an overload.
{}
所以 const
对值参数的传递方式没有任何影响。它们被复制。 const
仅影响参数在函数实现中的使用方式。