This may be a silly question, but still I'm a bit curious...
Recently I was working on one of my former colleague projects, and I've noticed that he really loved to use something like this:
int foo(7);
instead of:
int foo = 7;
Is this a normal/good way to do in C++ language?
Is there some kind of benefits to it? (Or is this just some silly programming style that he was into..?)
This really reminds me a bit of a good way how class member variables can be assigned in the class constructor... something like this:
class MyClass
{
public:
MyClass(int foo) : mFoo(foo)
{ }
private:
int mFoo;
};
instead of this:
class MyClass
{
public:
MyClass(int foo)
{
mFoo = foo;
}
private:
int mFoo;
};
For basic types there's no difference. Use whichever is consistent with the existing code and looks more natural to you.
Otherwise,
A a(x);
performs direct initialization, and
A a = x;
performs copy initialization.
The second part is a member initializer list, there's a bunch of Q&As about it on StackOverflow.
Both are valid. For builtin types they do the same thing; for class types there is a subtle difference.
MyClass m(7); // uses MyClass(int)
MyClass n = 3; // uses MyClass(int) to create a temporary object,
// then uses MyClass(const MyClass&) to copy the
// temporary object into n
The obvious implication is that if MyClass has no copy constructor, or it has one but it isn't accessible, the attempted construction fails. If the construction would succeed, the compiler is allowed to skip the copy constructor and use MyClass(int) directly.
All the answers above are correct. Just add that to it that C++11 supports another way, a generic one as they say to initialize variables.
int a = {2} ;
or
int a {2} ;
Several other good answers point out the difference between constructing "in place" (ClassType v(<constructor args>)) and creating a temporary object and using the copy constructor to copy it (ClassType v = <constructor arg>). Two additional points need to be made, I think. First, the second form obviously has only a single argument, so if your constructor takes more than one argument, you should prefer the first form (yes, there are ways around that, but I think the direct construction is more concise and readable - but, as has been pointed out, that's a personal preferance).
Secondly, the form you use matters if your copy constructor does something significantly different than your standard constructor. This won't be the case most of the time, and some will argue that it's a bad idea to do so, but the language does allow for this to be the case (all surprises you end up dealing with because of it, though, are your own fault).
It's a C++ style of initializing variables - C++ added it for fundamental types so the same form could be used for fundamental and user-defined types. this can be very important for template code that's intended to be instantiated for either kind of type.
Whether you like to use it for normal initialization of fundamental types is a style preference.
Note that C++11 also adds the uniform initialization syntax which allows the same style of initialization to be used for all types - even aggregates like POD structs and arrays (though user defined types may need to have a new type of constructor that takes an initialization list to allow the uniform syntax to be used with them).
Yours is not a silly question at all as things are not as simple as they may seem. Suppose you have:
class A {
public:
A() {}
};
and
class B {
public:
class B(A const &) {}
};
Writing
B b = B(A());
Requires that B's copy constructor be accessible. Writing
B b = A();
Requires also that B's converting constructor B(A const &) be not declared explicit. On the other hand if you write
A a;
B b(a);
all is well, but if you write
B b(A());
This is interpreted by the compiler as the declaration of a function b that takes a nameless argument which is a parameterless function returning A, resulting in mysterious bugs. This is known as C++'s most vexing parse.
I prefer using the parenthetical style...though I always use a space to distinguish from function or method calls, on which I don't use a space:
int foo (7); // initialization
myVector.push_back(7); // method call
One of my reasons for preferring using this across the board for initialization is because it helps remind people that it is not an assignment. Hence overloads to the assignment operator will not apply:
#include <iostream>
class Bar {
private:
int value;
public:
Bar (int value) : value (value) {
std::cout << "code path A" << "\n";
}
Bar& operator=(int right) {
value = right;
std::cout << "code path B" << "\n";
return *this;
}
};
int main() {
Bar b = 7;
b = 7;
return 0;
}
The output is:
code path A
code path B
It feels like the presence of the equals sign obscures the difference. Even if it's "common knowledge" I like to make initialization look notably different than assignment, since we are able to do so.
It's just the syntax for initialization of something :-
SomeClass data(12, 134);
That looks reasonable, but
int data(123);
Looks strange but they are the same syntax.
Related
Triggered by this answer I was reading in the core guidelines:
C.45: Don’t define a default constructor that only initializes data
members; use in-class member initializers instead
The reasoning given is
Reason
Using in-class member initializers lets the compiler generate the
function for you. The compiler-generated function can be more
efficient.
Note that this is specifically about a default constructor that does nothing but initialize the members and the guideline suggests that one should not write such a constructor.
The "bad" example is:
Example, bad
class X1 { // BAD: doesn't use member initializers
string s;
int i;
public:
X1() :s{"default"}, i{1} { }
// ...
};
The "good" example is using in-class member initializers and no user declared constructor:
Example
class X2 {
string s = "default";
int i = 1;
public:
// use compiler-generated default constructor
// ...
};
What can the compiler generated constructor do more efficient than the user-provided one in that particular example (or in any other example)?
Is the initializer list not giving the same opportunities for optimization as in-class initializers?
Short Answer
A defaulted constructor should have the same generated assembly as the equivalent initializer constructor provided that the author includes the correct constexpr and noexcept statuses.
I suspect the "can be more efficient" is referring to the fact that, in general, it will generate more optimal code than the equivalent developer-authored one that misses opportunities such as inline, constexpr, and noexcept.
Long Answer
An important feature that defaulted constructors perform is that they interpret and deduce the correct status for both constexpr and noexcept
This is something that many C++ developers do not specify, or may not specify correctly. Since Core Guidelines targets both new and old C++ developers, this is likely why the "optimization" is being mentioned.
The constexpr and noexcept statuses may affect code generation in different ways:
constexpr constructors ensure that invocations of a constructor from values yielded from constant expressions will also yield a constant expression. This can allow things like static values that are not constant to not actually require a constructor invocation (e.g. no static initialize overhead or locking required). Note: this works for types that are not, themselves, able to exist in a constexpr context -- as long as the constexprness of the constructor is well-formed.
noexcept may generate better assembly of consuming code since the compiler may assume that no exceptions may occur (and thus no stack-unwinding code is necessary). Additionally, utilities such as templates that check for std::is_nothrow_constructible... may generate more optimal code paths.
Outside of that, defaulted constructors defined in the class-body also make their definitions visible to the caller -- which allows for better inlining (which, again, may otherwise be a missed-opportunity for an optimization).
The examples in the Core Guidelines don't demonstrate these optimizations very well. However, consider the following example, which illustrates a realistic example that can benefit from defaulting:
class Foo {
int a;
std::unique_ptr<int> b;
public:
Foo() : a{42}, b{nullptr}{}
};
In this example, the following are true:
A construction of Foo{} is not a constant expression
Construction of Foo{} is not noexcept
Contrast this to:
class Foo {
int a = 42;
std::unique_ptr<int> b = nullptr;
public:
Foo() = default;
};
On the surface, this appears to be the same. But suddenly, the following now changes:
Foo{} is constexpr, because std::unique_ptr's std::nullptr_t constructor is constexpr (even though std::unique_ptr cannot be used in a full constant expression)
Foo{} is a noexcept expression
You can compare the generated assembly with this Live Example. Note that the default case does not require any instructions to initialize foo; instead it simply assigns the values as constants through compiler directive (even though the value is not constant).
Of course, this could also be written:
class Foo {
int a;
std::unique_ptr<int> b;
public:
constexpr Foo() noexcept :a{42}, b{nullptr};
};
However, this requires prior knowledge that Foo is able to be both constexpr and noexcept. Getting this wrong can lead to problems. Worse yet, as code evolves over time, the constexpr/noexcept state may become incorrect -- and this is something that defaulting the constructor would have caught.
Using default also has the added benefit that, as code evolves, it may add constexpr/noexcept where it becomes possible -- such as when the standard library adds more constexpr support. This last point is something that would otherwise be a manual process every time code changes for the author.
Triviality
If you take away the use of in-class member initializers, then there is one last worthwhile point mentioning: there is no way in code to achieve triviality unless it gets compiler-generated (such as through defaulted constructors).
class Bar {
int a;
public:
Bar() = default; // Bar{} is trivial!
};
Triviality offers a whole different direction on potential optimizations, since a trivial default-constructor requires no action on the compiler. This allows the compiler to omit any Bar{} entirely if it sees that the object is later overwritten.
I think that it's important to assume that C.45 refers to constants (example and enforcement):
Example, bad
class X1 { // BAD: doesn't use member initializers
string s;
int i; public:
X1() :s{"default"}, i{1} { }
// ... };
Example
class X2 {
string s = "default";
int i = 1; public:
// use compiler-generated default constructor
// ... };
Enforcement
(Simple) A default constructor should do more than just initialize
member variables with constants.
With that in mind, it's easier to justify (via C.48) why we should prefer in-class initializers to member initializers in constructors for constants:
C.48: Prefer in-class initializers to member initializers in
constructors for constant initializers
Reason
Makes it explicit that the same value is expected to be used in all
constructors. Avoids repetition. Avoids maintenance problems. It leads
to the shortest and most efficient code.
Example, bad
class X { // BAD
int i; string s;
int j; public:
X() :i{666}, s{"qqq"} { } // j is uninitialized
X(int ii) :i{ii} {} // s is "" and j is uninitialized
// ... };
How would a maintainer know whether j was deliberately uninitialized
(probably a poor idea anyway) and whether it was intentional to give s
the default value "" in one case and qqq in another (almost certainly
a bug)? The problem with j (forgetting to initialize a member) often
happens when a new member is added to an existing class.
Example
class X2 {
int i {666};
string s {"qqq"};
int j {0}; public:
X2() = default; // all members are initialized to their defaults
X2(int ii) :i{ii} {} // s and j initialized to their defaults
// ... };
Alternative: We can get part of the benefits from default arguments to
constructors, and that is not uncommon in older code. However, that is
less explicit, causes more arguments to be passed, and is repetitive
when there is more than one constructor:
class X3 { // BAD: inexplicit, argument passing overhead
int i;
string s;
int j; public:
X3(int ii = 666, const string& ss = "qqq", int jj = 0)
:i{ii}, s{ss}, j{jj} { } // all members are initialized to their defaults
// ... };
Enforcement
(Simple) Every constructor should initialize every member variable (either explicitly, via a delegating ctor call or via default
construction).
(Simple) Default arguments to constructors suggest an in-class initializer may be more appropriate.
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.
C++11 introduced this:
struct MyClass {
int foo = 0; //*
};
Until now I've been using this without thinking about it, but now I'm wondering:
Is this initialization doing/executing any actual initialization at this particular line (//* in the code), or is this a mere convenience notation that only does/executes something later, when the object is actually constructed?
Not sure what you mean by "later" and "at this particular line", but the above is equivalent to the following:
struct MyClass {
MyClass() : foo(0) { }
};
So if I understand your question correctly, then the answer is: "Yes, only when the object is actually constructed".
Declarations are not executable code, they do not execute anything. This is merely a convenient notation for inserting initialization of foo to zero into every constructor that you define (or into an implicitly defined default constructor, if you do not define any constructors yourself).
suppose we have a class
class Foo {
private:
int PARTS;
public:
Foo( Graph & );
int howBig();
}
int Foo::howBig() { return this->PARTS; }
int Foo::howBig() { return PARTS; }
Foo::Foo( Graph &G ) {
<Do something with G.*>
}
Which one of howBig()-variants is correct?
The &-sign ensures that only the reference for Graph object
is passed to initialization function?
In C I would simply do something like some_function( Graph *G ),
but in C++ we have both & and *-type variables, never understood
the difference...
Thank you.
When you've local variable inside a member function, then you must have to use this as:
Foo::MemberFunction(int a)
{
int b = a; //b is initialized with the parameter (which is a local variable)
int c = this->a; //c is initialized with member data a
this->a = a; //update the member data with the parameter
}
But when you don't have such cases, then this is implicit; you need to explicity write it, which means in your code, both versions of howBig is correct.
However, in member initialization list, the rules are different. For example:
struct A
{
int a;
A(int a) : a(a) {}
};
In this code, a(a) means, the member data a is being initialized with the parameter a. You don't have to write this->a(a). Just a(a) is enough. Understand this visually:
A(int a) : a ( a ) {}
// ^ ^
// | this is the parameter
// this is the member data
You can use this-> to resolve the dependent name issue without explicitly having to spell out the name of the base. If the name of the base is big this could arguably improve readability.
This issue only occurs when writing templates and using this-> is only appropriate if they're member functions, e.g.:
template <typename T>
struct bar {
void func();
};
template <typename T>
struct foo : public bar {
void derived()
{
func(); // error
this->func(); // fine
bar<T>::func(); // also fine, but potentially a lot more verbose
}
};
Which one of howBig()-variants is correct?
both in your case, the compiler will produce the same code
The &-sign ensures that only the reference for Graph object is passed to initialization function? In C I would simply do something like some_function( Graph *G ), but in C++ we have both & and *-type variables, never understood the difference...
there is no difference as per the use of the variable inside the method(except syntax) - in the case of reference(&) imagine as if you've been passed an invisible pointer that you can use without dereferencing
it(the &) might be "easier" for clients to use
Both forms of Foo::howBig() are correct. I tend to use the second in general, but there are situations that involve templates where the first is required.
The main difference between references and pointers is the lack of "null references". You can use reference arguments when you don't want to copy the whole object but you want to force the caller to pass one.
Both are correct. Usually shorter code is easier to read, so only use this-> if you need it to disambiguate (see the other answers) or if you would otherwise have trouble understanding where the symbol comes from.
References can't be rebound and can't be (easily) bound to NULL, so:
Prefer references to pointers where you can use them. Since they cannot be null and they cannot be deleted, you have fewer things to worry about when using code that uses references.
Use const references instead of values to pass objects that are large (more than say 16 or 20 bytes) or have complex copy constructors to save copy overhead while treating it as if it was pass by value.
Try to avoid return arguments altogether, whether by pointer or reference. Return complex object or std::pair or boost::tuple or std::tuple (C++11 or TR1 only) instead. It's more readable.
I've run into an issue I don't understand and I was hoping someone here might provide some insight. The simplified code is as follows (original code was a custom queue/queue-iterator implementation):
class B
{
public:
B() {};
class C
{
public:
int get();
C(B&b) : b(b){};
private:
B& b;
};
public:
C get_c() { return C(*this); }
};
int main()
{
B b;
B::C c = b.get_c();
c = b.get_c();
return EXIT_SUCCESS;
}
This, when compiled, gives me the following error:
foo.cpp: In member function 'B::C& B::C::operator=(const B::C&)':
foo.cpp:46: error: non-static reference member 'B& B::C::b', can't use default assignment operator
foo.cpp: In function 'int main()':
foo.cpp:63: note: synthesized method 'B::C& B::C::operator=(const B::C&)' first required here
I can go around this by using two separate C variables, as they are supposed to be independent 'C' objects, but this only hides the problem (I still don't understand why I can't do this).
I think the reason is that the reference cannot be copied, but I don't understand why. Do I need to provide my own assignment operator and copy constructor?
This problem has nothing to do with inner classes. In C++ you just can't (re)assign references - they need to be initialised when defined.
A simpler example is:
class B
{
public:
B(int& i) : ir(i) {};
int& ir;
};
int main()
{
int i;
B b(i); // Constructor - OK
int j;
B bb = B(j); // Copy constructor - OK
bb = b; // Assignment - Error
return 0;
}
A reference cannot be changed after being given its initial value. This means that it is impossible to write an assignment operator that changes the value of a reference member. If you need to do this, use a pointer instead of a reference.
Actually, there's a solution to this. You can implement operator= in terms of copy construction, and it will work :) It's a very capable technique for such cases. Assuming you do want to support assignment.
C++ doesn't have "inner classes", just nested class declarations. "inner classes" are a Java-ism that I don't think are found in other mainstream languages. In Java, inner classes are special because they contain an implicit immutable reference to an object of the containing type. To achieve the equivalent to C++'s nested declarations in Java requires use of static inner classes; static inner classes do not contain a reference to an object of the declaring type.