2016-11-23 28 views
18

今天在工作中,我遇到了一个我不明白的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; 
} 

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

$ 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. 

注意,对于my_ex我已经定义的构造不调用。接下来,如果我想实际抛出这个变量:

throw my_ex; 

我得到一个编译错误:

$ 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 

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

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; 

然后它按我的预期工作:

$ 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) 

我有以下问题:

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

回答

34

根据most vexing parse,MyException my_ex(std::string(text));是一个函数声明;函数名为my_ex,参数名称为text,类型为std::string,返回MyException。它根本不是对象定义,那么不会调用构造函数。

请注意错误信息undefined reference to 'my_ex(std::string)'throw my_ex;(您试图抛出函数指针),这意味着找不到函数my_ex的定义。

为了修正它可以添加额外的括号(如你已示出),或使用braces从C++ 11的支持:

MyException my_ex1((std::string(text))); 
MyException my_ex2{std::string(text)}; 
MyException my_ex3{std::string{text}}; 
+9

这可能是C++最令人生气的怪癖。 –

+1

@GillBates特别是在这样一个复杂的场景中。 – songyuanyao

+1

谢谢,我不知道这种语法,因此我对这种情况感到困惑。 –

4

的答案是使用{}(支撑-INIT)尽可能可能。但有时候,它可能会被无意中遗漏。幸运的是,编译器(如没有额外的警告标志铛)可以提示:

warning: parentheses were disambiguated as a function declaration [-Wvexing-parse] 
    MyException my_ex(std::string(text)); 
        ^~~~~~~~~~~~~~~~~~~ 
test.cpp:13:23: note: add a pair of parentheses to declare a variable 
    MyException my_ex(std::string(text)); 
        ^
         (    ) 
1 warning generated. 

它会立即指出你的问题。

相关问题