I found a page saying that int a = 12; and int a (12); do the same thing.
But is there something special with the int a (12); way of initializing a variables?

Like, you can do: string test(5, '-'); which would make test = -----
I couldn't seem to find a way to do the same using string the test = way.

string(size_t, char) is a constructor overload, the constructor is a function that initializes the class.

Primitive data types (like int, float, double, char) don't have constructors, nor do they have functions associated with them. In languages other than C++ (like C#) integer types to have a set of functions available, making them much more than "POD" or Plain Old Data.

i.e., in C#,

Int32 someInt = 128;
Console.WriteLine(someInt.ToString());

In C++ (assuming cout didn't support outputting an integer),

int someInt = 512;
string out;
stringstream(someInt) >> out;
cout << out << endl;

http://www.cplusplus.com/reference/string/string/string/

I found a page saying that int a = 12; and int a (12); do the same thing.

Indeed. There's also a third way in C++0x (where the added functionality prevents narrowing conversions):

int a{12}; // alternatively 'int a = {12};'

But is there something special with the int a (12); way of initializing a variables?

Sometimes it's the only way. One example would be in a constructor's initialization list. Another is for user-defined types that have an explicit constructor, the assignment initialization syntax is disallowed:

class foo {
public:
    foo(int) {}
};

class bar {
public:
    explicit bar(int) {}
};

int main()
{
    foo a = 11; // Okay, non-explicit constructor
    bar b = 11; // Error! Implicit construction not allowed
}

The constructor initialization can also introduce an ambiguity between a variable definition and a function declaration:

int a(int());

You might guess that this defines an int variable called a and initializes it with the default value of int. What it really does is declare a function called a that takes an unnamed int parameter and returns int.

Like, you can do: string test(5, '-'); which would make test = -----
I couldn't seem to find a way to do the same using string the test = way.

Correct. The assignment initialization only applies to "constructors" with a single parameter. I say "constructors" because the built-in types don't have constructors, yet the syntax still behaves as if they did.

commented: for mentioning function decl. syntax conflict +11

The form std::string test("hello"); is called a "direct-initialization". This is essentially a direct call to whatever constructor matches the parameters given. Direct-initialization is the only accepted form in a class constructor's initialization list.

The form std::string test = "hello"; is called a "copy-initialization", because it is meant as a initialization of the new object with a copy of another, and the standard does not permit much else (this will be expanded a bit in the upcoming standard). You will find the relevant clause in the C++ Standard 8.5/14. What is special about the copy-initialization can be summarized (extract from the standard text) to:

If it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression(s) as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.

Otherwise, user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3). If the conversion cannot be done or is ambiguous, the initialization is ill-formed.

In plain english, it means that the right-hand-side needs to be either of the same type as the left-hand-side or be implicitly convertible to it (means it can be converted without explicit syntax to indicate the conversion).


The difference is important because some people tend to assume that either syntax is the same, but it is not. Also, some people expect that the copy-initialization is like a construction and an assignment merged together, that is not the case either. People sometimes think that if you can do my_class a; a = b; then you can do my_class a = b; , it is not so, because the rules about assignment (which is just normal function overloading) are not the same as the rules about copy-initialization (as stated above). And the compiler will not take an ill-formed copy-initialization and turn it into a default-construction and an assignment.

class foo {
public:
    foo(int) {}
};

class bar {
public:
    explicit bar(int) {}
};

int main()
{
    foo a = 11; // Okay, non-explicit constructor
    bar b = 11; // Error! Implicit construction not allowed
}

Could someone explain that code?

Like...

* how can you do foo a = 11 ?
foo is a class, a the object. The constructor takes an int, so shouldn't it be
foo a (11) ?

* what does the "explicit" bar(... do? -why cant you do bar b = 11

* how can you have foo(int) ? don't you need a variable name? foo(int whatever) ?

how can you do foo a = 11 ?

How can you do int a = 11 ? Guess what? Classes support the same functionality.

foo is a class, a the object. The constructor takes an int, so shouldn't it be
foo a (11) ?

It could be, but since there's a constructor taking a single int, that constructor acts as a "conversion constructor" and the "assignment syntax" is allowed.

what does the "explicit" bar(... do? -why cant you do bar b = 11

Do you not have a book on C++? The explicit keyword disables the above described "assignment syntax" for construction.

how can you have foo(int) ? don't you need a variable name? foo(int whatever) ?

Unused parameters don't need a name.

Member Avatar for danb737

Could someone explain that code?

Like...

* how can you do foo a = 11 ?
foo is a class, a the object. The constructor takes an int, so shouldn't it be
foo a (11) ?

* what does the "explicit" bar(... do? -why cant you do bar b = 11

* how can you have foo(int) ? don't you need a variable name? foo(int whatever) ?

There are four things that the compiler will create for you in a class unless you tell it otherwise : a default constructor, a copy constructor, an assignment constructor and a destructor.

When you write in the example above foo a = 11; you are doing actually three things in one line ! First you create an object foo called a. This object is initialized without any parameter (no int given), so the compiler will just initialize it with something (0 most of the times, but I think it's actually undefined behavior). Next you try to assign to your object a an integer... The compiler doesn't like that too much. How is he able to deal between banana and apples (foo object and int) ? But he's got one last chance : he's looking if maybe he could instantiate an object foo with this 11 given. And it finds that actually you can construct a foo object with one int, so he does so. Now he can assign this foo object initialized with 11 to the 'a' object, by using the default assignment constructor, which by default will make a shallow copy.

When you use the explicit keyword in front of a constructor, you tell the compiler that it cannot use a default constructor. So in the example of writing bar b = 11; , if we follow the same steps as above, you will come to a halt when the compiler tries to assign 11 to object b, because it will try to create an object bar out of the 11 but will see that only an explicit constructor is allowed. So the only way you can create an object bar is by explicitly calling its constructor bar(some_integer).

It took me some time to understand this at first and got me confused several times. You can find more (and better) explanations here : http://www.learncpp.com/cpp-tutorial/911-the-copy-constructor-and-overloading-the-assignment-operator/ and http://www.learncpp.com/cpp-tutorial/912-shallow-vs-deep-copying/

There are four things that the compiler will create for you in a class unless you tell it otherwise : a default constructor, a copy constructor, an assignment constructor and a destructor.

Or none of them. While it's pedagogically useful to assume that the special member functions are always synthesized, reality is (as usual) more complicated. If a special member function is "trivial" as defined by the standard, the compiler need not actually synthesize it.

When you write in the example above foo a = 11; you are doing actually three things in one line ! First you create an object foo called a. This object is initialized without any parameter (no int given), so the compiler will just initialize it with something (0 most of the times, but I think it's actually undefined behavior).

I think you're confused. Since a non-explicit constructor exists which takes a single int, there's no reason for the compiler to do anything but call it directly.

Oh, and you need to look up the difference between implementation-defined behavior, unspecified behavior, and undefined behavior:

  • Implementation-defined Behavior: The behavior is well-defined, chosen by the compiler, and must be documented.
  • Unspecified Behavior: The behavior is well-defined, chosen by the compiler, and need not be documented.
  • Undefined Behavior: All bets are off. The program as a whole is released from any restrictions imposed by the standard.

And it finds that actually you can construct a foo object with one int, so he does so. Now he can assign this foo object initialized with 11 to the 'a' object, by using the default assignment constructor, which by default will make a shallow copy.

Or the compiler can simply construct a new foo object initialized with 11 in-place. By the way, what's this "assignment constructor"? Presumably you mean the copy constructor, but if that were the case one could easily disprove your explanation with a simple program. Have you even tested this process?

#include <iostream>

using namespace std;

class foo {
public:
    // Define all special member functions
    foo() { cout << "foo()\n"; }
    foo(const foo&) { cout << "foo(const foo&)\n"; }
    foo(foo&&) { cout << "foo(foo&&)\n"; }
    
    ~foo() { cout << "~foo()\n"; }
    
    foo& operator=(const foo&) { cout << "operator=(const foo&)\n"; return *this; }
    foo& operator=(foo&&) { cout << "operator=(foo&&)\n"; return *this; }
    
    // Define an implicit initialization constructor
    foo(int) { cout << "foo(int)\n"; }
};

int main()
{
    foo a = 11;
}

Sure, the compiler might be especially inefficient behind the scenes and hide it from you, but I challenge you to find a compiler that does so.

When you use the explicit keyword in front of a constructor, you tell the compiler that it cannot use a default constructor.

"Default constructor" already has a well understood definition, and it's not what you're talking about because the default constructor takes no arguments. When you use the explicit qualifier on a constructor, you tell the compiler that it can't use the implicit conversion syntax for that constructor.

It took me some time to understand this at first and got me confused several times.

You're still not quite there yet.

Member Avatar for danb737

Hey Narue,

Thanks a lot for all the clarifications ! Indeed I'm only a noob. But I tried to help another noob. I'm glad my post made you react and correct it. Now the OP will have an answer. :)

By assignment constructor, I meant assignment operator. But as you pointed out, I'm still not quite there yet. :)

In your example code, you write foo(foo&&) { cout << "foo(foo&&)\n"; . I guess you meant foo(foo&) { cout << "foo(foo&)\n"; ? Because I'm anaware of && (and my compiler seems to complain.

I tried your code out of curiosity, and it was very interesting to find out that there's only on call to a constructor. Indeed the compiler (hopefully) makes some good optimizations. I nevertheless thought it would be useful (though not always accurate) to make someone realize that it's not because you don't explicitly write a copy constructor (or constructor, etc) that you don't end up with one.

I'm sure you find all this so trivial. So sorry if this was a too "low level" answer.

Because I'm anaware of && (and my compiler seems to complain.

I included the move constructor and move assignment operator to account for the next C++ standard. If your compiler doesn't support rvalue references, just remove those member functions.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.