使用参数化构造函数时没有编译错误

Gáb*_*ncz 18 c++ most-vexing-parse

今天在工作中我遇到了一个我不懂的C++行为.我已经生成了以下示例代码来说明我的问题:

#include <string>
#include <iostream>

class MyException
{
    public:
        MyException(std::string s1) {std::cout << "MyException constructor, s1: " << s1 << std::endl;}
};

int main(){
    const char * text = "exception text";
    std::cout << "Creating MyException object using std::string(const char *)." << std::endl;
    MyException my_ex(std::string(text));
    std::cout << "MyException object created." << std::endl;
    //throw my_ex;

    std::string string_text("exception text");
    std::cout << "Creating MyException object using std::string." << std::endl;
    MyException my_ex2(string_text);
    std::cout << "MyException object created." << std::endl;
    // throw my_ex2;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码段编译时没有任何错误,并产生以下输出:

 $ g++ main.cpp
 $ ./a.out
Creating MyException object using std::string(const char *).
MyException object created.
Creating MyException object using std::string.
MyException constructor, s1: exception text
MyException object created.
Run Code Online (Sandbox Code Playgroud)

请注意,对于my_ex我定义的构造函数未调用.接下来,如果我想实际抛出这个变量:

throw my_ex;
Run Code Online (Sandbox Code Playgroud)

我收到编译错误:

 $ g++ main.cpp
/tmp/ccpWitl8.o: In function `main':
main.cpp:(.text+0x55): undefined reference to `my_ex(std::string)'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

如果我在转换周围添加大括号,就像这样:

const char * text = "exception text";
std::cout << "Creating MyException object using std::string(const char *)." << std::endl;
MyException my_ex((std::string(text)));
std::cout << "MyException object created." << std::endl;
throw my_ex;
Run Code Online (Sandbox Code Playgroud)

然后它按照我的预期工作:

 $ g++ main.cpp
 $ ./a.out
Creating MyException object using std::string(const char *).
MyException constructor, s1: exception text
MyException object created.
terminate called after throwing an instance of 'MyException'
Aborted (core dumped)
Run Code Online (Sandbox Code Playgroud)

我有以下问题:

  1. 为什么我的第一个例子编译?为什么我没有收到编译错误?
  2. 当我尝试时,为什么代码不能编译throw my_ex;
  3. 为什么大括号可以解决问题?

son*_*yao 34

根据最烦恼的解析,MyException my_ex(std::string(text));是一个功能声明; 该函数被命名my_ex,以一个以texttype 命名的参数std::string返回MyException.它根本不是对象定义,因此不会调用构造函数.

注意错误消息undefined reference to 'my_ex(std::string)'throw my_ex;(你想扔实际上是一个函数指针),这意味着无法找到函数的定义my_ex.

要修复它,您可以添加其他括号(如您所示)或使用C++ 11支持的大括号:

MyException my_ex1((std::string(text)));
MyException my_ex2{std::string(text)};
MyException my_ex3{std::string{text}};
Run Code Online (Sandbox Code Playgroud)

  • 这可能是C++中最令人愤怒的怪癖. (9认同)
  • 因为这个非常怪异我总是*尽可能使用大括号初始化. (8认同)
  • `MyException ex {{text}}`. (2认同)