首页 > 解决方案 > 通过引用传递隐式调用复制ctor以获得不兼容的参数?

问题描述

我正在使用以下旧代码模式进行调试输出。我意识到这不是打印调试消息的最有效方式,但我的问题涉及更基本的问题。这似乎是一个基本问题,但它挑战了我对编译器如何解释指定为通过常量引用传递的函数参数的理解。

遗留代码中的调试消息模式如下所示:

#include <iostream>
#include <cctype>
#include <cstring>
#include <stdio.h>



void debugMsg(const std::string& testStringRef){
    printf("%s\n", testStringRef.c_str());
}

int main() {

#if defined(DEBUG_MSG_OUT)
    char debug_message[512];
    snprintf(debug_message,512, "TESTING 12345678910!");
    debugMsg(debug_message);
#endif
    return 0;
}

在这个例子今天引起我的注意之前,我会说它不应该编译,因为 debugMsg 接受 const 字符串引用的传递,它是用 char[] 调用的。但它会在运行时编译并输出预期的字符串。

这挑战了我对传递引用函数参数的理解(我意识到这是基本的 C++ 知识,但这对我来说是新的)。我认为按引用函数参数的主要优点之一是避免在按值传递中发生的复制构造。我原以为不允许通过引用参数传递隐式参数转换,而是编译错误。但对我来说,即使 debugMsg 是按引用传递的函数,它看起来仍然是一个临时字符串对象。

我正在查看这段代码的反汇编,但没有看到对 std::string 的复制构造函数的调用。有人可以用低级细节澄清这里发生的事情吗?如果实际上 char[] 被隐式转换为 std::string 然后这个对象被传递给 debugMsg() 为什么这允许在 C++ 中发生特定的通过引用函数?

反汇编调试消息

标签: c++pass-by-referencecopy-constructor

解决方案


这个是正常的。如果有一个非显式的合格构造函数,它将被用作转换。从字符串文字创建字符串使用char const *构造函数。(这就是为什么您看不到复制构造函数的原因——它仅在我们复制 std::string 时被调用,但在这种情况下,我们是从文字创建一个,因此使用了不同的构造函数。)

然后,您的问题归结为:“我很惊讶临时(右值)可以绑定到对 const 的左值引用”。自 1998 年标准化以来,c++ 一直如此。但是,如果您尝试将临时值绑定到非 const左值引用,则确实存在您预期的错误。这个想法是,如果它是一个可修改的左值引用,该函数将改变它的值。由于写入临时文件几乎总是一个错误,并且这样做没有很好的论据,因此不允许这样做。但是允许将临时值绑定到对 const 值的引用,因为它仅用作只读输入,并且临时值的持续时间至少与绑定到它的左值引用的生命周期一样长。它有用且安全。


推荐阅读