C++ 常量参数传递:为什么编译器不自动设置为按引用传递

c++ const argument passing: why compilers do not automatically set to pass-by-reference

提问人:Mako 提问时间:6/26/2021 更新时间:6/26/2021 访问量:247

问:

我了解到,对于非基元类型的常量参数,将它们作为引用传递到函数中比作为值传递更有效:

  • 效率不高的版本:

    void funcA(const std::string myString)

  • 高效版:

    void funcA(const std::string&myString)

由于高效版本似乎是一个显而易见的选择,我想知道为什么 C++ 编译器不以这种方式自动优化效率低下的版本?

C++ 常量 按引用传递

评论

3赞 StoryTeller - Unslander Monica 6/26/2021
没有什么是完全免费的。当您通过引用传递时,您不能再假设您的数据是数据的唯一视图。这可能会阻止编译器优化访问。
2赞 Igor Tandetnik 6/26/2021
这样的“优化”可能会改变程序的含义。 可能正在调用另一个函数,该函数可能会修改原始字符串。第一个版本不会遵守此修改,第二个版本会。funcA
0赞 Mako 6/30/2021
@IgorTandetnik 我尝试了两个版本的 funcA 的“funcA 调用另一个函数,它修改了原始字符串”,但它们都没有编译。类似于 void funcA(const std::string& myString) {changeMe(myStr);}错误:将“const string {aka const std::__cxx11::basic_string<char>}”绑定到类型为“std::__cxx11::string&”{aka std::__cxx11::basic_string<char>&}“的引用会丢弃限定符
0赞 Igor Tandetnik 6/30/2021
@Mako 像这样的东西
0赞 Mako 6/30/2021
@IgorTandetnik 感谢您的代码示例。现在我明白了你的第一条评论。

答:

2赞 rawrex 6/26/2021 #1

即使在副本的情况下也有优化。是的,一般来说,当函数参数按值传递时,编译器需要制作副本(因此本地副本和外部(原始)对象之间没有连接)。编译器也允许省略副本,这意味着当源是右值时,使用原始对象本身。

不要复制函数参数。相反,按值和 让编译器进行复制。- cpp.next.com

“按值”和“按引用”语义上存在差异我们从引用传递中获得的“优化”更像是一个结果,而不是一个目标,一个从我们在程序中表达的逻辑和含义派生出来的结果。

另外,考虑到即使在这个范围内引用是 ,我们仍然有一个引用(对另一个独立的对象)。意味着这个对象仍然可以被一些外部(在我们的范围内)力修改。const

最后,我们应该首先努力使语言表达的清晰度,而不是寻求过早的优化

评论

0赞 Mako 6/30/2021
我认为对于一些void funcA(const std::string&myString),我们想要表达的逻辑和含义是:输入参数是一个常量,函数应该/不能改变它。添加的“&”只是对性能的优化。当一个引用真的“仍然可以被一些外部(在我们的范围内)力量修改”时,我想这会损害原来的含义。但是,我无法找出一些外部来源修改变量的真实示例。有人可以举个例子吗?
0赞 rawrex 6/30/2021
@Mako 如果有多个执行线程对同一对象进行操作(我的意思是受保护和有效的使用,想象一下由两个线程共享的锁)。是的,如果不需要引用,则有助于避免复制,但它的本质不是优化技术。稍后会进行优化。
0赞 Mako 6/30/2021
在下面的评论中,我最初的问题 IgorTandetnik 给出了以下示例: godbolt.org/z/9T5xx1367 .您的线程示例也有帮助。现在,我看到可以在函数之外更改引用的情况,该函数将其作为常量。而且我一直认为使用通过常量引用传递是危险的......它有助于避免复制,但它可能会破坏我们想要为函数参数表达的真正含义(常量)。我不认为谁想在可能更改时指定“const”。谁能启发我?