When to use {} () in constructors - c++

In Game.h, I have a class named Game:
class Game
{
public:
Game();
void run();
private:
sf::Event e;
sf::RenderWindow app;
sf::Clock delay;
unsigned counter = 0;
Ice *ball = new Ice(app);
Players *players = new Players(app);
Collision collision;
void handleEvent();
};
Then, in Game.cpp, I use:
Game::Game() : app({1000,800},"NAME")
{
}
The syntax
Game::Game() : app(sf::VideoMode(1000,800),"NAME")
{
}
also works.
My question is: why can I omit sf::VideoMode in the first case, and if I do so, why do I HAVE to use {} for the videomode parameters? Using () in the first case results in an error.

Your Game constructor is calling the following sf::RenderWindow constructor:
RenderWindow (VideoMode mode, const String &title, Uint32 style=Style::Default, const ContextSettings &settings=ContextSettings())
You have to pass it a fully constructed sf::VideoMode object.
Both of your examples are constructing a temporary VideoMode object inline in the sf::RenderWindow constructor call. They are both calling the following sf::VideoMode constructor, just using different syntaxes:
VideoMode (unsigned int modeWidth, unsigned int modeHeight, unsigned int modeBitsPerPixel=32)
C++11 introduced a new feature called "Uniform Initialization", which unifies various different types of initialization syntaxes used in different contexts into a single syntax using curly braces, thus greatly simplifying coding. In this case, List Initialization is being used to initialize a temporary object using a braced-init-list. It is this feature that allows your {1000,800} example to construct a temporary sf::VideoMode object directly in a function parameter without having to explicitly state its class name.
Earlier C++ versions do not have "Uniform Initialization". In those versions, constructors can only be called explicitly by name. That is what allows your sf::VideoMode(1000,800) example to construct a temporary sf::VideoMode object (and it is still valid syntax in C++11 and later, too).
(1000,800) by itself is not valid C++ syntax for constructing an object, in any C++ version.

why can I omit sf::VideoMode in the first case
Because app's constructor's first parameter is declared as having type sf::VideoMode already.
It's the same reason you can write long v = 1; instead of having to write long v = long{1}; or something like that: the compiler knows the type of the variable or parameter being initialised, and can check that that type supports construction using the initialiser you specified, even if the initialiser doesn't have the same type.
and if I do so, why do I HAVE to use {} for the videomode parameters?
Because (1000,800) already had a different much older meaning: it means "get the value 1000, discard that, then get the value 800 instead". Admittedly that'd be pointless in this case, but there's no way of rewriting the language in such a way that (1000,800) works in your case while simultaneously sensible previously valid code continues to work too.

Related

C++ int pointer retroactively dereferences self

I've recently begun using C++ to try and program an Arduino library for a project I'm working on. In this library, I'm including another library published on GitHub, which I assume compiles on its own. As a part of the constructor for my class, I am creating and assigning an object of the published class. When I call the constructor, which takes two integers, with two integers, I get the following error:
Cell.cpp:7:31: error: no match for call to '(DS3904) (int&, int)'
_digipot(digipotAddress, 2);
^
EDIT: I was told by the comments before I edited this that a reference should work out just fine in this instance. Here is the library I am using. Following are the header file:
Cell.h:
#ifndef Cell_h
#define Cell_h
#include "Arduino.h"
#include "DS3904.h"
class Cell {
public:
Cell(int cellNumber, int digipotAddress, int resistorAddress);
void setCellVoltage(int voltage);
int getCellNumber();
private:
unsigned int _cellNo;
unsigned int _resistorAddress;
DS3904 _digipot;
};
#endif
And the actual C++ file, Cell.cpp (note that some unused functions are omitted from this one):
#include "Arduino.h"
#include "Cell.h"
Cell::Cell(int cellNumber, int digipotAddress, int resistorAddress) {
_digipot(digipotAddress, 2);
_cellNo = cellNumber;
_resistorAddress = resistorAddress;
}
This actually doesn't have anything to do with pointers or references. You've got the wrong syntax for calling the constructor of the member object _digipot, and your code gets parsed as something different that results in a confusing error message.
You have a class Cell which has a member _digipot that is of type class DS3904. So your constructor for Cell needs to construct _digipot, but in C++, this isn't done by calling _digipot's constructor in the body of your Cell constructor. Instead it needs to be done in a member initializer list. So the correct way to write your constructor Cell::Cell would be:
Cell::Cell(int cellNumber, int digipotAddress, int resistorAddress)
: _digipot(digipotAddress, 2),
_cellNo(cellNumber),
_resistorAddress(resistorAddress)
{
// no code needed in the body
}
The idea is that in C++, there should never be any point in the program where you can see an object that exists but has not been fully constructed, with the one exception being that object's own constructor. If it was up to the body code of Cell::Cell to call _digipot's constructor, then it could also try to access _digipot before calling the constructor, at which point it would find it in an unconstructed state. So _digipot has to be constructed before the body of Cell::Cell starts execution, yet there still needs to be a way to specify which constructor of _digipot should be called, and with what arguments. Member initializer lists were invented to achieve this.
(You don't technically have to include the int members _cellNo and _resistorAddress in the member initializer list: if you leave them out, they get initialized to indeterminate values, and you can then assign to them in the body of the constructor like your existing code does. But it's cleaner to do everything in the member initializer list.)
So where did the weird error message come from? There are actually two error messages for your code, of which you only posted the second one, and the first one is the more informative one:
Cell-old.cpp: In constructor ‘Cell::Cell(int, int, int)’:
Cell-old.cpp:4:67: error: no matching function for call to ‘DS3904::DS3904()’
4 | Cell::Cell(int cellNumber, int digipotAddress, int resistorAddress) {
|
That's the first problem. You didn't specify a member initializer list, but _digipot still has to be constructed, so the default is for the object's default constructor to be called, i.e. a constructor taking no arguments. But class DS3904 doesn't have such a constructor, so this is an error.
The second issue is that your statement _digipot(digipotAddress, 2); in the body of the constructor isn't parsed as an attempt to call _digipot's constructor (after all, that should be impossible, since by the time we get here it should already have been constructed). Instead, a statement of the form obj(arg, arg) is applying the function call operator operator() to obj. If obj were a function or a function pointer, this would simply call the function, but this operator can also be overloaded for other types; see Why override operator()? for some examples of where this is useful.
So the compiler looks for an overloaded DS3904::operator() taking arguments compatible with what you've passed: an int lvalue, which could be passed as a reference (int&), and an int rvalue, which would have to be passed by value. No such overload exists, so this results in your second error.
By the way, clang's error messages on this code are a bit clearer:
Cell-old.cpp:4:7: error: constructor for 'Cell' must explicitly initialize the member '_digipot' which does not have a default constructor
Cell::Cell(int cellNumber, int digipotAddress, int resistorAddress) {
^
./Cell.h:15:16: note: member is declared here
DS3904 _digipot;
^
./DS3904.h:27:7: note: 'DS3904' declared here
class DS3904
^
Cell-old.cpp:5:5: error: type 'DS3904' does not provide a call operator
_digipot(digipotAddress, 2);
^~~~~~~~
When faced with a confusing error message, it's often helpful to try a different compiler, and see if it can give you something more useful.

Different ways of initializing an object in c++

Imagine this class:
class Entity {
public:
int x, y;
Entity() : x(0), y(0) { }
Entity(int x, int y) : x(x), y(y) { }
}
And here are multiple ways of initializing the class with what I think I know:
Entity ent1; //Uses the default constructor, so x=0 and y=0
Entity ent2(); //Uses the default constructor, so x=0 and y=0 (Not sure)
Entity ent3(1, 2); //Made constructor, so x=1 and y=2
Entity ent4 = Entity(); //Default constructor, so x=0 and y=0
Entity ent5 = Entity(2, 3); //Made constructor, so x=2 and y=3
I know that's it's possible to make an object on the heap memory, but that's not what I am looking for at this moment.
My question is, what's the difference between these ways of initializing an object?
I'm not sure which one I should use when.
The difference in initialization lies not only in form it takes, but also
in type of entity which is being initialized. In this case it's a class-type object with a defined default constructor, as well as a constructor with parameters.
Entity ent1;
The statement above is default initialization which result in a call of default constructor for the class Entity.
Entity ent2();
The declaration above will be treated by compiler as a function prototype if that's possible. Entity would be returned type of a function ent2, which takes no arguments. It's known as a case of most vexing parse (MVP) and its existence led to appearance of misleading "clever dumb rule": "never use parenthesis".
In statement like this a user-defined constructor that matches list of arguments is invoked for ent3 object:
Entity ent3(1, 2); // calls Entity(int x, int y)
Another case where MVP can strike is something like this:
Entity ent3_1(int(a), int(b)); // It's not what it looks like.
ent3_1 above is not a variable. The statement declares a function with two int parameters. int(a) being same as int a is legacy of C language and declaration syntax there, which ignores "extra" parenthesis.
Entity ent4 = Entity();
ent4 is a proper version of ent2 case until C++11. Default constructor is invoked as part of value initialization. Its form allows to avoid an ambiguity solving principle which makes ent2 and ent3_1 incorrect. Equal sign here is not an assignment, for no operator= call will happen here. It's part of declaration syntax meant to markup the initialization expression.
Entity ent5 = Entity(2, 3);
ent5 is a version of ent3 case. User-defined constructor invoked as part of value initialization.
Your question is tagged as C++11, and C++11 allows uniform initialization syntax:
Entity ent12{}; // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {}; // Not an assignment
Entity ent15 = Entity{2, 3}; // Not an assignment either!
Note that uniform initialization syntax has a caveat. E.g. this line
std::vector<int> v(10);
declares a vector of 10 elements. But this one
std::vector<int> v{10};
declares a vector initialized with single element of type int with value 10. This happens because std::vector has a constructor with following signature defined:
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
In case that you can't use neither () without triggering MVP nor {} without invoking undesired constructor, the value initialization assignment syntax allows to resolve the issue.
Addendum: Must watch CppCon 2018: Nicolai Josuttis “The Nightmare of Initialization in C++”

How to define a Struct with default values?

Rather surprised to find this question not asked before. Actually, it has been asked before but the questions are VERY DIFFERENT to mine. They are too complicated and absurd while I'll keep it simple and to the point. That is why this question warrants to be posted.
Now, when I do this,
struct A {
int a = -1;
};
I get the following error:
ANSI C++ forbids in-class initialization of non-const static member a
Now, along with the workaround can someone please tell me THE BEST way of initializing a struct member variable with a default value?
First, let's look at the error:
ANSI C++ forbids in-class initialization of non-const static member a
Initialization of a true instance member, which resides within the memory of an instance of your struct is the responsibility of this struct's constructor.
A static member, though defined inside the definition of a particular class/struct type, does not actually reside as a member of any instances of this particular type. Hence, it's not subject to explaining which value to assign it in a constructor body. It makes sense, we don't need any instances of this type for the static member to be well-initialized.
Normally, people write member initialization in the constructor like this:
struct SomeType
{
int i;
SomeType()
{
i = 1;
}
}
But this is actually not initialization, but assignment. By the time you enter the body of the constructor, what you've done is default-initialize members. In the case of a fundamental type like an int, "default-initialization" basically boils down to "eh, just use whatever value was in those bytes I gave you."
What happens next is that you ask i to now adopt the value 1 via the assignment operator. For a trivial class like this, the difference is imperceptible. But when you have const members (which obviously cannot be tramped over with a new value by the time they are built), and more complex members which cannot be default-initialized (because they don't make available a visible constructor with zero parameters), you'll soon discover you cannot get the code to compile.
The correct way is:
struct SomeType
{
int i;
SomeType() : i(1)
{
}
}
This way you get members to be initialized rather than assigned to. You can initialize more than one by comma-separating them. One word of caution, they're initialized in the order of declaration inside your struct, not how you order them in this expression.
Sometimes you may see members initialized with braces (something like i{1} rather i(c)). The differences can be subtle, most of the time it's the same, and current revisions of the Standard are trying to smooth out some wrinkles. But that is all outside the scope of this question.
Update:
Bear in mind that what you're attempting to write is now valid C++ code, and has been since ratification of C++11. The feature is called "Non-static data member initializers", and I suspect you're using some version of Visual Studio, which still lists support as "Partial" for this particular feature. Think of it as a short-hand form of the member initialization syntax I described before, automatically inserted in any constructor you declare for this particular type.
You could make a default constructor
struct A {
A() : a{-1} {}
int a;
};

When should we not use initialization list in the constructor?

Can someone please quote an example code when we should not use initialisation list in the constructor and how that can be overcome with assignment?
I am looking for an example for the below statement
This might happen when your class has two constructors that need to initialize the this object's data members in different orders. Or it might happen when two data members are self-referential. Or when a data-member needs a reference to the this object, and you want to avoid a compiler warning about using the this keyword prior to the { that begins the constructor's body (when your particular compiler happens to issue that particular warning). Or when you need to do an if/throw test on a variable (parameter, global, etc.) prior to using that variable to initialize one of your this members.
I believe the main concept that the author of your statement was referring to is the fact that calls made to variables in the initialisation list occur not in the order you see them in the initialisation list, but in the order the variables are listed in the class definition.
That means
if you have two different constructors which use initialisation lists, they must initialise them in the same sequence
your control over sequencing (which may be important if you have mutually-dependent members) is limited
I'd recommend taking a look at Scott Meyer's Effective C++ which covers this (amongst many, many other useful and informative topics).
Here are some examples:
This might happen when your class has two constructors that need to
initialize the this object's data members in different orders.
class Example1 {
public:
Example1(std::string decoded, std::string encoded)
: decoded_(decoded),
encoded_(encoded) {}
explicit Example1(std::string encoded)
: decoded_(), // Can't use "decoded_(Decode())" since "encoded_" isn't initialised
encoded_(encoded) {
decoded_ = Decode(); // Assign here instead of initialising
}
private:
std::string Decode(); // decodes class member "encoded_"
std::string decoded_, encoded_;
};
In this example, decoded_ will always be initialised before encoded_ since that's the order in which they are declared in the class, even if we swap their order in the initialisation list.
Or when a data-member needs a reference to the this object, and you
want to avoid a compiler warning about using the this keyword prior to
the { that begins the constructor's body (when your particular
compiler happens to issue that particular warning).
class Example2 {
public:
Example2() : functor_() {
functor_ = std::bind(&Example2::Do, this);
}
private:
void Do();
std::function<void()> functor_;
};
Here, functor_ needs to use this when it is initialised/assigned. If we were to intialise functor_ in the initialisation list, the this pointer would be referring to an object which at that point wasn't fully initialised. That could be safe depending on the particular circumstances, but the foolproof option is to defer setting functor_ until inside the constructor body, by which point this does refer to a fully-initialised object.
Or when you need to do an if/throw test on a variable (parameter,
global, etc.) prior to using that variable to initialize one of your
this members.
class Example3 {
public:
Example3(int force, int acceleration)
: force_(force),
acceleration_(acceleration),
mass_(0) {
if (acceleration_ == 0)
throw std::exception("Can't divide by 0");
mass_ = force_ / acceleration_;
}
private:
int force_, acceleration_, mass_;
};
Hopefully this is self-explanatory.
I'm not sure what is meant by
when two data members are self-referential
so I can't give an example for that I'm afraid.

Array converted implicitly to container class when passed as argument in C++

I was working on a project and, while playing around with the code, I came across the following peculiar occurrence.
I have two classes. The first holds three floats in an array representing Cartesian coordinates and defines a method to get those points;
class foo
{
protected:
float m_Coordinates[3];
public:
foo(float coordinates[3]);
void GetPoints(int resultArray[]);
};
foo::foo(int coordinates[3])
{
std::copy(coordinates, coordinates+3, m_Coordinates);
}
void foo::GetPoints(float resultArray[])
{
std::copy(m_Coordinates, m_Coordinates+3, resultArray);
}
The second class also stores an array of floats, but its constructor uses foo as a wrapper class to pass the values:
class bar
{
protected:
float m_MoreCoordinates[3];
public:
bar(foo f);
};
bar::bar(foo f)
{
f.GetPoints(m_MoreCoordinates);
//m_MoreCoordinates is passed by reference, so the values in
//m_MoreCoordinates are equal to the values in f.m_Coordinates
//after this line executes
}
Please ignore the fact that the approach I've taken to this code is simply horrible. It started out as an experiment in using arrays. Passing them as arguments, getting them as return types etc.
OK. Here's where I noticed something strange. If I declare an array of floats and pass them as an argument to bar's constructor, the compiler will generate an instance of class foo and pass that to bar for me. See example code below:
int main(int argv, char** argc)
{
float coordinates[] = {1.0f, 2.1f, 3.0f};
//Here the compiler creates an instance of class foo and passes
//coordinates as the argument to the constructor. It then passes
//the resulting class to bar's constructor.
bar* b = new bar(coordinates);
//Effectively, the compiler turns the previous line into
//bar* b = new bar(foo(coordinates));
return 0;
}
When I saw this, I thought it was a pretty neat feature of the code and was wondering how and why it happened. Is it safe to do this? I don't understand how it works, and so I don't want to depend on it. If someone could explain how this works, I'd really appreciate it.
Edit:
Thanks to Mankarse for pointing out how the conversion would be performed in the main. Initially, I had:
//Effectively, the compiler turns the previous line into
//bar* b = new bar(*(new foo(coordinates)));
As you guessed, compiler is implicitly creating a foo object and passing it to bar. Generally, this is considered a bit dangerous as the foo gets constructed without knowledge, to avoid this you can declare foos constructor as explicit. In that case compiler will not implicitly create foo from array of floats and you will get an compiler error.
When you think about it, you use this all of the time. Consider the following:
void foo(std::string argument);
Then, suppose you invoke this function using a string literal:
foo("argument");
this is the same as:
std::string argument("argument");
foo(argument);
It's a pretty useful feature.