gotw 80 syntax - initialisation in parameter list - c++

Gotw 80 includes the following example:
// Example 1
//
#include <string>
using namespace std;
class A
{
public:
A( const string& s ) { /* ... */ }
string f() { return "hello, world"; }
};
class B : public A
{
public:
B() : A( s = f() ) {}
private:
string s;
};
int main()
{
B b;
}
The article goes to discuss why the line s = f() is incorrect - due to object lifetimes and order of construction. The article states that at the time, the error wasn't picked up by the compiler.
However, ignoring the problems of order of intialisation and object lifetime, I don't see how s = f() in the parameter list of the constructor can be legal syntactically - it appears to be trying to initialise a member in the parameter list (or perhaps declaring a default value). Can anyone explain what this syntax is trying to do?

It looks like the intention was to call f() and assign the result to B::s. Afterward, the result of that assignment (which is s) would be used as actual parameter when calling the inherited A constructor.
It's syntactically valid. Replace s in that expression with some non-member variable, and g++ accepts it without issue. You might see similar syntax used more often with ordinary function calls instead of constructor calls.

Syntactically it's legal... when you have a base class with a constructor that takes arguments you can of course pass any expression as parameter:
strut A {
A(int) {}
};
struct B : A {
B() : A( any expression that returns an int ) {}
};
The problem is that when evaluating the expression in the example the object is not even yet a fully constructed A instance, so that code is invalid for two distinct reasons:
Calls a method of A of an non-instance (the constructor didn't start yet): f() call is illegal.
Assigns to a member that hasn't been initialized: s=... is illegal.

Related

How c++ resolve name in this case? [duplicate]

class C {
T a;
public:
C(T a): a(a) {;}
};
Is it legal?
Yes it is legal and works on all platforms.
It will correctly initialize your member variable a, to the passed in value a.
It is considered by some more clean to name them differently though, but not all. I personally actually use it a lot :)
Initialization lists with the same variable name works because the syntax of an initialization item in an initialization list is as follows:
<member>(<value>)
You can verify what I wrote above by creating a simple program that does this: (It will not compile)
class A
{
A(int a)
: a(5)//<--- try to initialize a non member variable to 5
{
}
};
You will get a compiling error something like: A does not have a field named 'a'.
On a side note:
One reason why you may not want to use the same member name as parameter name is that you would be more prone to the following:
class A
{
A(int myVarriable)
: myVariable(myVariable)//<--- Bug, there was a typo in the parameter name, myVariable will never be initialized properly
{
}
int myVariable;
};
On a side note(2):
One reason why you may want to use the same member name as parameter name is that you would be less prone to the following:
class A
{
A(int myVariable_)
{
//<-- do something with _myVariable, oops _myVariable wasn't initialized yet
...
_myVariable = myVariable_;
}
int _myVariable;
};
This could also happen with large initialization lists and you use _myVariable before initializing it in the initialization list.
One of the things that may lead to confusion regarding this topic is how variables are prioritized by the compiler. For example, if one of the constructor arguments has the same name as a class member you could write the following in the initialization list:
MyClass(int a) : a(a)
{
}
But does the above code have the same effect as this?
MyClass(int a)
{
a=a;
}
The answer is no. Whenever you type "a" inside the body of the constructor the compiler will first look for a local variable or constructor argument called "a", and only if it doesn't find one will it start looking for a class member called "a" (and if none is available it will then look for a global variable called "a", by the way). The result is that the above statment "a=a" will assign the value stored in argument "a" to argument "a" rendering it a useless statement.
In order to assign the value of the argument to the class member "a" you need to inform the compiler that you are referencing a value inside this class instance:
MyClass(int a)
{
this->a=a;
}
Fine, but what if you did something like this (notice that there isn't an argument called "a"):
MyClass() : a(a)
{
}
Well, in that case the compiler would first look for an argument called "a" and when it discovered that there wasn't any it would assign the value of class member "a" to class member "a", which effectively would do nothing.
Lastly you should know that you can only assign values to class members in the initialization list so the following will produce an error:
MyClass(int x) : x(100) // error: the class doesn't have a member called "x"
{
}
if the formal parameter and the member is named same then beware of using this pointer inside constructor to use the member variable
class C {
T a;
public:
C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};
Legal: yes, as explained by Brian, compiler knows the name to expect in the initializer list must be a member (or a base class), not anything else.
Good style: most likely not - for a lot of programmers (including you, it seems) the result is not obvious. Using a different name for the parameter will keep the code legal and make it a good style at the same time.
I would prefer writing some of:
class C {
T a_;
public:
C(T a): a_(a) {}
};
class C {
T a;
public:
C(T value): a(value) {}
};
The problem with this practice, legal though it may be, is that compilers will consider the variables shadowed when -Wshadow is used, and it will obfuscate those warnings in other code.
Moreover, in a non-trivial constructor, you make make a mistake, forgetting to put this-> in front of the member name.
Java doesn't even allow this. It's bad practice, and should be avoided.
Hey guys this is a great question. If you want to identical names for fields and constructor parameters / methods parameter you have to use scope resolution ( :: ) operator or you can use this ( this-> ) to map the parameter value with member like this please check the code snippet carefully you can understand easyly.
class Student{
private :
string name;
int rollNumber;
public:
Student()
{
// default constructor
}
// parameterized constructor
Student(string name, int rollNumber)
{
this->name = name;
Student::rollNumber = rollNumber;
}
void display()
{
cout<<"Name: "<<name <<endl;
cout<<"Roll Number: "<<rollNumber<<endl;
}
void setName(string name)
{
this->name = name;
}
void setrollNumber(int rollNumber)
{
Student::rollNumber = rollNumber;
}
};

What is this way of assignment called? myVar(value);

I was digging in somebody else's code where I noticed he assigns the public/private members of a class in the following way:
myMemberVar(Value);
instead of
myMemberVal=Value;
I'm wondering if this way of assigning is normal and can be really used interchangebally.
It's likely that you're looking at initialisations in the member initialisation list.
struct A
{
int x, y;
A()
: x(42) // <-- here
, y(12) // <-- and here
{}
{};
These are not "assignments", any more than the following are assignments:
void foo()
{
int x = 42;
int y = 42;
}
But recall that the C++03 initialisation syntax (as opposed to the above confusing, legacy, looks-like-assignment syntax†) is:
void foo()
{
int x(42);
int y(42);
}
And, going further, since C++11:
void foo()
{
int x{42};
int y{42};
}
And that's the syntax that's required in the member initialisation list.
Note that this means they're not generally interchangeable: only in an initialisation! Usually when you write = you're performing assignment and this initialisation syntax would be invalid there.
† Don't worry, I still prefer it too!
That is the syntax for construction, not assignment.
The first snippet of code doesn't assign anything; it attempts to call myMemberVar like a function.
Perhaps the real code was in the initialiser list of a constructor:
MyClass() : myMemberVar(Value) {}
while the second was in the constructor body:
MyClass() {
myMemberVar = Value;
}
The difference here is that the first performs direct-initialisation, not assignment; the second performs default-initialisation followed by assignment.
For simple types, both have the same effect, and can be regarded as interchangable. For class types, they might call different user-defined functions: a conversion/copy/move constructor in the first case, and a default constructor followed by an assignment operator in the second. Depending on how those functions are defined, the two options may have different effects or performance characteristics, and may not be possible if the required functions aren't accessible.

Is there a way to late-initialize a member variable (a class) in C++?

I am coming from the Java background. I have the following program.
#include <string>
#include <iostream>
class First {
public:
First(int someVal): a(someVal) {
}
int a;
};
class Second {
public:
First first;
Second() { // The other option would be to add default value as ": first(0)"
first = First(123);
}
};
int main()
{
Second second;
std::cout << "hello" << second.first.a << std::endl;
}
In class Second, I wanted to variable first to remain uninitialized until I specifically initialize it in Second()'s constructor. Is there a way to do it? Or am I just left with 2 options?:
Provide a parameter-less constructor.
Initialize it with some default value and later re-assign the required value.
I can't initialize first in the initializer-list with the right value, since the value is obtained after some operation. So, the actual required value for first is available in Second() constructor only.
MY suggestion: Use a function:
private: static int calculate_first(int input) {return input*5;}
explicit Second(int input) : first(calculate_first(input)) {}
Base classes will be initialized in the order they're declared in the class inheritance list, and then members will be initialized in the order that they're listed in the class, so the calculation can depend on non-static member-variables and base classes if they have already been initialized.
Alternatively:
Default constructor, then reassign:
explicit Second(int input) { first = input*5; }
Dummy value, then reassign:
explicit Second(int input) : first(0) { first = input*5; }
Use boost::optional (or std::optional as of C++17):
boost::optional<First> first;
explicit Second(int input) { first = input*5; }
Use the heap:
std::unique_ptr<First> first;
explicit Second(int input) { first.reset(new First(input*5));}
Second(const Second& r) first(new First(*(r->first))) {}
Second& operator=(const Second& r) {first.reset(new First(*(r->first)));}
Placement new:
This is tricky and not suggested
and worse in every way than boost::optional
So sample deliberately missing.
But it is an option.
Initialize first in the member initializer list.
It may help to perform your calculations in a helper function and use a forwarding constructor:
class Second {
public:
Second() : Second(helper_function()) {}
private:
Second(int calc): first(calc) {}
static int helper_function() { return ...; }
First first;
};
This sentence is the core of the problem:
I can't initialize first in the initializer-list with the right value,
since the value is obtained after some operation.
You should know that what you want to do here is not perfect programming style in Java, either. Leaving the field with some default value and then assigning it a bit later after some calculations have been done effectively prevents it from being final, and consequently the class from being immutable.
In any case, your goal must be to push those calculations directly into the initialization of the member, using private helper functions (which may be static):
class Second {
private:
First first;
static int getInitializationData()
{
// complicated calculations go here...
return result_of_calculations;
}
public:
Second() : first(getInitializationData()) {}
};
In my opinion, everything else is just a workaround and will complicate your life in the long run.
You can just do what you said in the comments, or, you can make first a pointer to First and give it memory whenever you like, although i don't recommend this way
One way to separate object lifetimes is to use the heap, make first a pointer and initialize it anytime you like:
class Second {
public:
First* first;
Second() {
first = new First(123);
}
};
of course, you'll probably want to use a smart pointer of some sort rather than a raw pointer.
If you don't code to explicitly initialize a member variable, the default initializer is used to initialize it.
The draft C++ standard has the following about initialization of base classes and member variables:
12.6 Initialization [class.init]
1 When no initializer is specified for an object of (possibly cv-qualified) class type (or array thereof), or the initializer has the form (), the object is initialized as specified in 8.5.
And
12.6.1 Explicit initialization [class.expl.init]
1 An object of class type can be initialized with a parenthesized expression-list, where the expression-list is construed as an argument list for a constructor that is called to initialize the object. Alternatively, a single assignment-expression can be specified as an initializer using the = form of initialization. Either direct-initialization semantics or copy-initialization semantics apply; see 8.5.

C++: how to pass a variable as an argument to class constructor

I am faced with a very puzzling issue. I am trying to construct an object using a variable as a parameter.
Have a look at this code please:
#include <iostream>
class A {
public:
A() : val(0) {};
A(int v) : val(v) {};
private:
int val;
};
main() {
int number;
A a; /* GOOD, object of type A, created without arguments */
A b(2); /* GOOD, object of type A, created with one argument */
A c(); /* BAD, C++ thinks this is declaration of
a function returning class A as a type */
A(d); /* GOOD, object of type A again; no arguments */
A(number); /* BAD, tries to re-declare "number" as object of type A */
}
I think I do understand why objects "a", "b" and "d" can be created, whereas the rest can not.
But I would really need the syntax of the last declaration, i.e.
A(number);
to create a temporary object, to pass as an argument to another object.
Any idea how to work around it?
Kind regards
Your intention is to create a temporary object, but this object would also be anonymous : you have no way to refer to it after the semicolon.
There is no point in creating an anonymous temporary object just to discard it. You have to instantiate your temporary directly at the call site of the ctor/method that will consume it.
Solution
To pass an anonymous temporary object to a function, you actually need to instantiate it inside the arguments' list :
functionExpectingA(A(number));
For the line of "c declaration", you are poking at the most vexing parse. If you actually need to pass a default constructed A object as an argument to another object constructor, you need to add another pair of braces to do the trick (so the compiler can distinguish it from a function declaration) :
class OtherClass
{
public:
OtherClass(A a)
{
//...
};
};
OtherClass obj((A()));
^ ^
EDIT #1 : jrok pointed out that the argument given to A constructor is not enough to resolve the ambiguity.
If you need to pass an anonymous temporary object that is built with an argument, there is no ambiguity (so no need for the extra parentheses), you still need the parentheses around the anonymous object construction.:
OtherClass obj((A(number)));
C heritage : a single argument is not enough
EDIT #2 : "why giving a single argument to A constructor does not resolve the ambiguity".
What happens with OtherClass obj(A(number)); ?
This is a declaration for a function named obj, taking an A object as its unique argument. This argument is named number.
i.e: It is exactly equivalent to OtherClass obj(A number);. Of course, you can omit the argument name at function declaration. So it is also sementically equivalent to OtherClass obj(A);
The syntax with parentheses around the object name is inherited from C :
int(a); // declares (and defines) a as an int.
int a; // strictly equivalent.
What with more arguments to the constructor then ?
If you added a ctor to OtherClass taking two (or more) arguments :
OtherClass(A a1, A a2)
{
//...
};
Then this syntax :
A arg1, arg2;
OtherClass obj(A(arg1, arg2));
Would this time actually declare obj as an instance of OtherClass.
This is because A(arg1, arg2) cannot be interpreted as name declaration for an A. So it is actually parsed as the construction of an anonymous A object, using the constructor with 2 parameters.

Can I use identical names for fields and constructor parameters?

class C {
T a;
public:
C(T a): a(a) {;}
};
Is it legal?
Yes it is legal and works on all platforms.
It will correctly initialize your member variable a, to the passed in value a.
It is considered by some more clean to name them differently though, but not all. I personally actually use it a lot :)
Initialization lists with the same variable name works because the syntax of an initialization item in an initialization list is as follows:
<member>(<value>)
You can verify what I wrote above by creating a simple program that does this: (It will not compile)
class A
{
A(int a)
: a(5)//<--- try to initialize a non member variable to 5
{
}
};
You will get a compiling error something like: A does not have a field named 'a'.
On a side note:
One reason why you may not want to use the same member name as parameter name is that you would be more prone to the following:
class A
{
A(int myVarriable)
: myVariable(myVariable)//<--- Bug, there was a typo in the parameter name, myVariable will never be initialized properly
{
}
int myVariable;
};
On a side note(2):
One reason why you may want to use the same member name as parameter name is that you would be less prone to the following:
class A
{
A(int myVariable_)
{
//<-- do something with _myVariable, oops _myVariable wasn't initialized yet
...
_myVariable = myVariable_;
}
int _myVariable;
};
This could also happen with large initialization lists and you use _myVariable before initializing it in the initialization list.
One of the things that may lead to confusion regarding this topic is how variables are prioritized by the compiler. For example, if one of the constructor arguments has the same name as a class member you could write the following in the initialization list:
MyClass(int a) : a(a)
{
}
But does the above code have the same effect as this?
MyClass(int a)
{
a=a;
}
The answer is no. Whenever you type "a" inside the body of the constructor the compiler will first look for a local variable or constructor argument called "a", and only if it doesn't find one will it start looking for a class member called "a" (and if none is available it will then look for a global variable called "a", by the way). The result is that the above statment "a=a" will assign the value stored in argument "a" to argument "a" rendering it a useless statement.
In order to assign the value of the argument to the class member "a" you need to inform the compiler that you are referencing a value inside this class instance:
MyClass(int a)
{
this->a=a;
}
Fine, but what if you did something like this (notice that there isn't an argument called "a"):
MyClass() : a(a)
{
}
Well, in that case the compiler would first look for an argument called "a" and when it discovered that there wasn't any it would assign the value of class member "a" to class member "a", which effectively would do nothing.
Lastly you should know that you can only assign values to class members in the initialization list so the following will produce an error:
MyClass(int x) : x(100) // error: the class doesn't have a member called "x"
{
}
if the formal parameter and the member is named same then beware of using this pointer inside constructor to use the member variable
class C {
T a;
public:
C(T a): a(a) {
this->a.sort ;//correct
a.sort();//will not affect the actual member variable
}
};
Legal: yes, as explained by Brian, compiler knows the name to expect in the initializer list must be a member (or a base class), not anything else.
Good style: most likely not - for a lot of programmers (including you, it seems) the result is not obvious. Using a different name for the parameter will keep the code legal and make it a good style at the same time.
I would prefer writing some of:
class C {
T a_;
public:
C(T a): a_(a) {}
};
class C {
T a;
public:
C(T value): a(value) {}
};
The problem with this practice, legal though it may be, is that compilers will consider the variables shadowed when -Wshadow is used, and it will obfuscate those warnings in other code.
Moreover, in a non-trivial constructor, you make make a mistake, forgetting to put this-> in front of the member name.
Java doesn't even allow this. It's bad practice, and should be avoided.
Hey guys this is a great question. If you want to identical names for fields and constructor parameters / methods parameter you have to use scope resolution ( :: ) operator or you can use this ( this-> ) to map the parameter value with member like this please check the code snippet carefully you can understand easyly.
class Student{
private :
string name;
int rollNumber;
public:
Student()
{
// default constructor
}
// parameterized constructor
Student(string name, int rollNumber)
{
this->name = name;
Student::rollNumber = rollNumber;
}
void display()
{
cout<<"Name: "<<name <<endl;
cout<<"Roll Number: "<<rollNumber<<endl;
}
void setName(string name)
{
this->name = name;
}
void setrollNumber(int rollNumber)
{
Student::rollNumber = rollNumber;
}
};