Instance variable initialization in C++ private area - c++

In class A,counter b(5); doesn't work.
while counter a; (the call of the default constructor) works.
Why? Is it not possible to call a parameterized constructor for an instance variable?
class counter {
private:
int value;
public:
counter() { this->value = 0; }
counter(int value) { this->value = value; }
};
class A {
private:
// works
counter a;
// works (since C++11)
int x = 5;
// doesn't work
counter b(5);
};
int main()
{
// works
counter myCounter;
// works as well
counter mySecondCounter(5);
return 0;
}

If allowed, counter b(5); technically declares a function named b that returns a counter object by value, and takes a single argument that's an integer.
While that, very likely, would not be the intention of the coder, that's why it is not allowed.
In Bjarne's words about this rule for In-Class Initializers:
We can specify an initializer for a non-static data member in the class declaration. For example:
class A {
public:
int a {7};
int b = 77;
};
For pretty obscure technical reasons related to parsing and name lookup, the {} and = initializer
notations can be used for in-class member initializers, but the () notation cannot.

It is possible. Change
counter b(5);
to
counter b = counter(5);
It is perhaps more elegant to initialise in a constructor intialisation list.
class A {
private:
A() : b(5) {}
counter a;
int x = 5;
counter b;
};

You have four options:
class A {
private:
counter C1{5};
// Works, only with single parameter constructors
counter C2 = 5;
// Works, with any number of parameters
counter C3 = counter(5);
counter C4;
// Constructor initializer list, works with any number of parameters
A() : C4(5) {}
};

In C++, this is not the correct syntax for initializing members with default values.
There are two options to solve it:
1.use operator =
counter b = counter(5);
2.use constructor with initialization list
A() : a(),b(5) {}

Related

How to pass the reference of the class "Randomer" without constructor to a class via constructor. How does the class Randomer work?

I'm trying to store the reference of the class "Randomer" initiated in "main" to another class.
What would be best approach, the pointer or reference?
How does the class "Randomer" takes is initial values.
How does this work?
operator()()
size_t operator()() {
return dist_(gen_);
}
Randomer taken from: https://www.mmbyte.com/
class Randomer {
// random seed by default
std::mt19937 gen_;
std::uniform_int_distribution<size_t> dist_;
public:
/* ... some convenient ctors ... */
Randomer(size_t min, size_t max, unsigned int seed = std::random_device{}())
: gen_{seed}, dist_{min, max} {
}
// if you want predictable numbers
void SetSeed(unsigned int seed) {
gen_.seed(seed);
}
size_t operator()() {
return dist_(gen_);
}
};
someClass{
protected:
Randomer& random;
public:
someClass(){
this->random = ....; // <----------------------
this->random{0, 9}; // this doesn't work.
}
someClass(Randomer& random){
this->random = random; // <----------------------
}
}
int main()
{
Randomer randomer{0, 9}; // how does this work?
someClass* test = new someClass(randomer);
int randomNumber = randomer(); // // how does this work?
std::cout << "randomNumber" << randomNumber << endl;
return 0;
}
Result in error:
error: constructor for 'someClass' must explicitly initialize the member 'random' which does not have a default constructor.
The error applies to default constructor as the overloaded constructor.
Edit:
If I try reference:
someClass{
protected:
Randomer& random;
public:
someClass(): : random(new Randomer{0,9}){ // this doesn't work either
}
someClass(): random{0}{ // <------ error 1
}
someClass(): random{0,9}{ // <------ alternative, error 2
}
someClass(Randomer& random): random(random){ // all good
this->random = random;
}
void somefunction(){
int randomNumber = this->random(); // no complaing
}
}
int main()
{
Randomer randomer{0, 9}; // is created here
someClass* some = new someClass;
someClass* some2 = new someClass(randomer);
}
Error:
1: No matching constructor for initialization of 'Randomer &'
2: Non-const lvalue reference to type 'Randomer' cannot bind to an initializer list temporary
The default constructor needs "Randomer"
otherwise error:
Constructor for 'someClass' must explicitly initialize the reference member 'random'.
I would like to have both constructors.
The best bet is to get via reference.
Both constructors of someClass initialize the random member too late. By the time the constructor body is called, all members are either initialized from the member initializer list, or default-initialized.
Randomer does not have a default initializer, so that is what the compiler is complaining about.
To fix that problem, write a member initializer list:
someClass(Randomer& random) : random(random) {}
The default constructor has an extra issue: it needs to construct a Randomer& but has no way of freeing the returned object when someClass is destroyed. You could either switch to std::shared_ptr<Randomer> and then let natural reference counting take care of it, or you could take a reference to a static Randomer shared across all someClass objects if that fits your requirements:
class someClass {
// Note: inline static is a C++17 feature. You will need
// to split declaration and definition in older C++ versions.
static inline Randomer global_randomer{0, 9};
public:
someClass() : randomer{global_randomer} {}
};
As for your other questions:
operator()() is simply the function call operator (fully spelled out: operator()), and you're defining it without any parameters, so you add an empty argument list.
Brace initialization is new in C++11.
Passing Randomer by reference is fine, assuming the "source" remains in scope. If not you might want to use a std::shared_ptr<Randomer> instead, so it is kept alive for as long as a shared_ptr to it exists.

Using a non static value as default argument in a function

Is there a nice way to have a non static value as default argument in a function? I've seen some older responses to the same question which always end up in explicitly writing out the overload. Is this still necessary in C++17?
What I'd like to do is do something akin to
class C {
const int N; //Initialized in constructor
void foo(int x = this->N){
//do something
}
}
instead of having to write
class C {
const int N; //Initialized in constructor
void foo(){
foo(N);
}
void foo(int x){
//do something
}
}
which makes the purpose of the overload less obvious.
One relatively elegant way (in my opinion) would be to use std::optional to accept the argument, and if no argument was provided, use the default from the object:
class C {
const int N_; // Initialized in constructor
public:
C(int x) :N_(x) {}
void foo(std::optional<int> x = std::nullopt) {
std::cout << x.value_or(N_) << std::endl;
}
};
int main() {
C c(7);
c.foo();
c.foo(0);
}
You can find the full explanation of what works/doesn't work in section 11.3.6 of the standard. Subsection 9 describes member access (excerpt):
A non-static member shall not appear in a default argument unless it
appears as the id-expressionof a class member access expression
(8.5.1.5) or unless it is used to form a pointer to member
(8.5.2.1).[Example:The declaration of X::mem1()in the following example
is ill-formed because no object is supplied for the non-static
memberX::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a);// error: non-static memberaused as default argument
int mem2(int i = b);// OK; useX::b
static int b;
};

Initializing A Variable With Its Default Constructor

Question:
Is there a difference between the following initializations?
(A) What exactly is the second one doing?
(B) Is one more efficient than the other?
int variable = 0;
int variable = int();
This question also applies to other data types such as std::string:
std::string variable = "";
std::string variable = std::string();
Background:
I basically got the idea here (the second code sample for the accepted answer) when I was trying to empty out a stringstream.
I also had to start using it when I began learning classes and realized that member variable initializations had to be done in the constructor, not just following its definition in the header. For example, initializing a vector:
// Header.h
class myClass
{
private:
std::vector<std::string> myVector;
};
// Source.cpp
myClass::myClass()
{
for (int i=0;i<5;i++)
{
myVector.push_back(std::string());
}
}
Any clarity on this will be greatly appreciated!
Edit
After reading again, I realized that you explicitely asked about the default constructor while I provided a lot of examples with a 1 parameter constructor.
For Visual Studio C++ compiler, the following code only executes the default constructor, but if the copy constructor is defined explicit, it still complains because the never called copy constructor can't be called this way.
#include <iostream>
class MyInt {
public:
MyInt() : _i(0) {
std::cout << "default" << std::endl;
}
MyInt(const MyInt& other) : _i(other._i) {
std::cout << "copy" << std::endl;
}
int _i;
};
int main() {
MyInt i = MyInt();
return i._i;
}
Original (typo fixed)
For int variables, there is no difference between the forms.
Custom classes with a 1 argument constructor also accept assignment initialization, unless the constructor is marked as explicit, then the constructor call Type varname(argument) is required and assignment produces a compiler error.
See below examples for the different variants
class MyInt1 {
public:
MyInt1(int i) : _i(i) { }
int _i;
};
class MyInt2 {
public:
explicit MyInt2(int i) : _i(i) { }
int _i;
};
class MyInt3 {
public:
explicit MyInt3(int i) : _i(i) { }
explicit MyInt3(const MyInt3& other) : _i(other._i) { }
int _i;
};
int main() {
MyInt1 i1_1(0); // int constructor called
MyInt1 i1_2 = 0; // int constructor called
MyInt2 i2_1(0); // int constructor called
MyInt2 i2_2 = 0; // int constructor explicit - ERROR!
MyInt2 i2_3 = MyInt2(0); // int constructor called
MyInt3 i3_1(0); // int constructor called
MyInt3 i3_2 = 0; // int constructor explicit - ERROR!
MyInt3 i3_3 = MyInt3(0); // int constructor called, copy constructor explicit - ERROR!
}
The main difference between something like:
int i = int(); and int i = 0;
is that using a default constructor such as int() or string(), etc., unless overloaded/overridden, will set the variable equal to NULL, while just about all other forms of instantiation and declarations of variables will require some form of value assignment and therefore will not be NULL but a specific value.
As far as my knowledge on efficiency, neither one is "better".

Temporaries created during assignment operation

if every assignment creates a temporary to copy the object into lvalue, how can you check to see in VC++ 8.0?
class E
{
int i, j;
public:
E():i(0), j(0){}
E(int I, int J):i(I), j(J){}
};
int main()
{
E a;
E b(1, 2);
a = b //would there be created two copies of b?
}
Edit:
Case 2:
class A
{
int i, j;
public:
A():i(0), j(0){}
};
class E
{
int i, j;
A a;
public:
E():i(0), j(0){}
E(int I, int J):i(I), j(J){}
E(const E &temp)
{
a = temp; //temporary copy made?
}
};
int main()
{
E a;
E b(1, 2);
a = b //would there be created two copies of b?
}
From your comment, you made it clear that you didn't quite understand this C++-FAQ item.
First of all, there are no temporaries in the code you presented. The compiler declared A::operator= is called, and you simply end up with 1 in a.i and 2 in a.j.
Now, regarding the link you provided, it has to do with constructors only. In the following code :
class A
{
public:
A()
{
s = "foo";
}
private:
std::string s;
};
The data member s is constructed using std::string parameterless constructor, then is assigned the value "foo" in A constructor body. It's preferable (and as a matter of fact necessary in some cases) to initialize data members in an initialization list, just like you did with i and j :
A() : s("foo")
{
}
Here, the s data member is initialized in one step : by calling the appropriate constructor.
There are a few standard methods that are created automatically for you if you don't provide them. If you write
struct Foo
{
int i, j;
Foo(int i, int j) : i(i), j(j) {}
};
the compiler completes that to
struct Foo
{
int i, j;
Foo(int i, int j) : i(i), j(j)
{
}
Foo(const Foo& other) : i(other.i), j(other.j)
{
}
Foo& operator=(const Foo& other)
{
i = other.i; j = other.j;
return *this;
}
};
In other words you will normally get a copy constructor and an assignment operator that work on an member-by-member basis. In the specific the assignment operator doesn't build any temporary object.
It's very important to understand how those implicitly defined method works because most of the time they're exact the right thing you need, but sometimes they're completely wrong (for example if your members are pointers often a member-by-member copy or assignment is not the correct way to handle the operation).
This would create a temporary:
E makeE( int i, int j )
{
return E(i, j);
}
int main()
{
E a;
a = makeE( 1, 2 );
E b = makeE( 3, 4 );
}
makeE returns a temporary. a is assigned to the temporary and the assignment operator is always called here. b is not "assigned to", as it is being initialised here, and requires an accessible copy-constructor for that to work although it is not guaranteed that the copy-constructor will actually be called as the compiler might optimise it away.

Default Constructors

I know that default constructors initialize objects to their default values, but how do we view these values? If there's a variable of type int, it is supposed to be initialized to 0. But how do we actually view these default values of the constructors? Can anyone please provide a code snippet to demonstrate the same?
Unless specified otherwise, objects are constructed with their default constructor, only if one is available.
And for example ints are not initialized.
This is a common source of huge troubles and bugs, because it can have any value.
So the rule is , always initialise your variables, and for a class you do it in the initialization list
class A
{
private:
int i;
float f;
char * pC;
MyObjectType myObject;
public:
A() : // the initialisation list is after the :
i(0),
f(2.5),
pC(NULL),
myObject("parameter_for_special_constructor")
{}
}
}
In C++, int is not a class and does not have a default (or any other) constructor.
An int is not guaranteed to be initialised to 0.
If you have a class that has an int as an attribute, you should explicitly initialise it in each of the class's constructors (not just the default one).
class sample
{
private:
int x;
public:
sample()
:x(0)
{
}
sample(const int n)
:x(n)
{
}
sample(const sample& other)
:x(other.x)
{
}
// [...]
};
This way you (and users of your class) can "view" the default values.
Good coding practice: write your own constructor, so you know how it will be initialized. This is portable and guaranteed to always have the same behaviour. Your code will be easier to read and the compiler knows how to make that efficient, especially when using the special notation:
class Foo
{
public:
Foo() : i(0), j(0) {}
private:
int i;
int j;
};
AFAIK, if T is a type (not necessarily a class), T() returns a default value for the type T. Here's a small test I ran:
int main()
{
char c = char();
int i = int();
cout << "c = " << hex << (int) c << endl;
cout << "i = " << i << endl;
}
The output is:
c = 0
i = 0
Default constructors do not automatically initialise ints to 0. You can use parentheses to indicate the default value though.
struct X
{
int x;
};
struct X x1; // x1.x is not necessarily 0
struct Y
{
int y;
Y() : y()
{
}
};
struct Y y1; // y1.y will be 0
show your code
And if your int value is a member of class .
you must give it a value in your default constructor func
The default constructor is which can be invoked with 0 parameters. For example
struct X
{
X(int x = 3) //default constructor
{
//...
}
};
It initializes the object to whichever state you code it to initialize. However, if you don't define any constructor at all the compiler will attempt to generate a default constructor for you - which, in turn is equivalent to a constructor with no arguments and no body. That means that all the members of class/struct type will be initialized with their def. ctors and all the members of primitive types like int will remain uninitialized. Please note that I specialy noted that the compiler will attempt to generate a dflt ctor, because it can fail to do so, for example when one or more members of the class do not have default constructors. HTH
AS soon as you have created an object start printing the values such as ob.x.
Thats the only way u can know what default constructor has assigned to the variables.