Gábor Ferencz Gábor Ferencz - 9 days ago 3
C++ Question

C++ - Absence of compilation error when using parametrized constructor

Today at work I came across a behavior in C++ which I don't understand. I have produced the following example code to illustrate my problem:

#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;
}


This code snippet compiles without any errors and produces the following output:

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


Note that for
my_ex
the constructor I have defined was not called. Next, if I want to actually throw this variable:

throw my_ex;


I get a compilation error:

$ 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


If I add braces around the conversion, like this:

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;


Then it works as I would have expected:

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


I have the following questions:


  1. Why does my first example compile? How come I don't get a compilation error?

  2. Why doesn't the code compile, when I try to
    throw my_ex;
    ?

  3. Why do the braces resolve the problem?


Answer

According to most vexing parse, MyException my_ex(std::string(text)); is a function delcaration, not an object declaration; which is a function named my_ex, taking a parameter named text with type std::string, returns MyException.

Note the error message undefined reference to 'my_ex(std::string)' for throw my_ex;, which means that can't find the definition of the function my_ex;

To fix it you can add additional parentheses (as you has shown) or use braces which supported from C++11:

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