使用参数化构造函数时没有编译错误
Absence of compilation error when using parametrized constructor
今天在工作中我遇到了一个我不理解的 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)
我有以下问题:
- 为什么我的第一个示例可以编译?为什么我没有得到编译错误?
- 当我尝试
throw my_ex;
时,为什么 没有 代码编译?
- 为什么牙套能解决问题?
根据most vexing parse,MyException my_ex(std::string(text));
是一个函数声明;该函数名为 my_ex
,采用名为 text
的参数,类型为 std::string
、returns MyException
。根本就不是对象定义,那么就不会调用构造函数。
注意 throw my_ex;
的错误信息 undefined reference to 'my_ex(std::string)'
(你实际上是在尝试抛出一个函数指针),这意味着找不到函数的定义 my_ex
.
要修复它,您可以添加额外的括号(如您所示)或使用 C++11 支持的 braces:
MyException my_ex1((std::string(text)));
MyException my_ex2{std::string(text)};
MyException my_ex3{std::string{text}};
答案是尽可能使用{}
(braced-init)。但有时,它可能会在不经意间错过。幸运的是,编译器(如 clang,在没有额外警告标志的情况下)可以提示:
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.
这会立即指出问题所在。
今天在工作中我遇到了一个我不理解的 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)
我有以下问题:
- 为什么我的第一个示例可以编译?为什么我没有得到编译错误?
- 当我尝试
throw my_ex;
时,为什么 没有 代码编译? - 为什么牙套能解决问题?
根据most vexing parse,MyException my_ex(std::string(text));
是一个函数声明;该函数名为 my_ex
,采用名为 text
的参数,类型为 std::string
、returns MyException
。根本就不是对象定义,那么就不会调用构造函数。
注意 throw my_ex;
的错误信息 undefined reference to 'my_ex(std::string)'
(你实际上是在尝试抛出一个函数指针),这意味着找不到函数的定义 my_ex
.
要修复它,您可以添加额外的括号(如您所示)或使用 C++11 支持的 braces:
MyException my_ex1((std::string(text)));
MyException my_ex2{std::string(text)};
MyException my_ex3{std::string{text}};
答案是尽可能使用{}
(braced-init)。但有时,它可能会在不经意间错过。幸运的是,编译器(如 clang,在没有额外警告标志的情况下)可以提示:
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.
这会立即指出问题所在。