i'm newbie in c++ languge, and i'm fimiliar with java language.
in Java world, the code looks ok , but not in c++.
can someone please explain why the both constructors are called?
class Position {
public:
Position(void)
{
std::cout<<"defualt constructor\n";
}
Position(unsigned int row,unsigned int col)
{
std::cout<<"two Arguments constructor\n";
row_index = row;
col_index = col;
}
private:
unsigned int row_index;
unsigned int col_index;
};
class Tool
{
public:
Tool(char Team,unsigned int row,unsigned int col)
{
pos = Position(row,col);
team = Team;
}
std::string To_string()
{
std::string str = "team: ";
str+= team;
str+= " pos: ";
str+= pos.To_string();
return str;
}
char Get_team()
{
return team;
}
private:
Position pos;
char team; // A or B
};
int main(void)
{
Tool t = Tool('A',1,3);
return 0;
}
i intended to call for the two arguments constructor
OUTPUT:
defualt constructor
two Arguments constructor
In the Tool class the Position object is first default constructed before the execution of the Tool constructor body is executed. Then you create a new temporary Position object in the Tool constructor body, and use it to assign to pos.
The important part here is that object construction is a three-step process:
The object is allocated
The object is initialized and all its members are constructed (here the Position default constructor is called)
The constructor of the object is executed (here the two-argument Position constructor is called)
To only use the two-argument Position constructor, and not simply assign to the pos object, you need to use an constructor initializer list. You do this by modifying the Tool constructor as this:
Tool(char Team,unsigned int row,unsigned int col)
: pos(row, col), // Initializes the `pos` object
team(Team) // Initialize the `team` member
{
// No code needed, the members have already been initialized
}
In C++, all member variables are constructed before the body of the constructor is entered. Your code default automatically constructs a Position, and then in the body of the constructor creates another Position and assigns it to the previously constructed one.
You need to pass the parameters of Position using an initialisation list:
Tool(char Team,unsigned int row,unsigned int col) : pos( row, col ), team(Team) {
// constructor now empty
}
In general, the body of a constructor should be empty.
When the execution enters constructor body, member objects, of the owning class, need to be constructed (default constructor is used, if no explicit call to constructor is specified).
Upon entering the constructor body, Position(row,col) in pos = Position(row,col); creates a temporary Position object, which gets assigned to pos.
If you want to avoid calling default constructor, of member objects, in such a case, use initialize members in an initializer-list:
Tool(char Team,unsigned int row,unsigned int col)
: pos (row, col), team (Team)
{
}
Why the code, in Java, works, as you expect, is due to the fact, that you, always, operate on references to objects, rather than on objects, as values. And non-initialized member object references in Java, would be default initialized to null (if memory serves right), until you create an object, and assign a reference to it, to a member variable.
Related
Here is the code:
#include<iostream>
using namespace std;
class Rectangle
{
private :
int _width;
int _height;
public :
Rectangle()
: _width{},_height{}
{}
Rectangle(int initial_w, int initial_h)
: _width{initial_w}, _height{initial_h}
{}
int get_width(){return _width;}
};
int main()
{
Rectangle a;
Rectangle(2,3);
cout<<a.get_width()<<endl;
}
I don't understand why it returns 0, i thought it is supposed to be 2.
Please help!!!!!
In your main method, you create a Rectangle a;, which calls your default constructor Rectangle(). Then in the next line you create a temporary element with Rectangle(2,3);, which calls your initialization constructor Rectangle(int initial_w, int initial_h), but it is discarded immediately, as you have not assigned it to a variable. Finally, you output your default-constructed variable a.
It seems what you want to achieve is this:
int main()
{
Rectangle a(2, 3);
cout << a.get_width() << endl;
}
Let's Look at your code within main() line by line:
Rectangle a;
Rectangle(2,3);
cout<<a.get_width()<<endl;
In the first line, you are creating an instance of a Rectangle Object and it is using the default constructor which can in truth be any value as the member variables are not initialized to 0 directly or some other value.
In your second line of code, you are using the classes constructor without declaring it as a variable object while not assigning it to any previously existing variable instance which in turn creates a temporary that will be constructed and destroyed before you even call std::cout.
In your third statement, you are using your class's get_width() message which is returning exactly what the default constructor initialized the member variable to when you declared the variable a.
There are a few ways to fix this:
Rectangle a(2,3);
std::cout << a.get_width() << '\n';
Rectangle b = Rectangle(4,5);
std::cout << b.get_width() << '\n';
The first line uses the user-defined constructor which is preferred in many cases. The second line requires the use of the copy constructor and assignment operator, here it's fairly trivial so, the default versions of these are used. However, in more complex classes and classes that will use the heap and dynamic memory will require the use of the copy constructor and assignment operator to be user-defined.
if constructor is used for allocating memory.
In the following program it does not work like that.
See
#include <iostream>
using namespace std;
class Demo
{
int i;
public:
Demo()
{
cout<<"\nDefault contructor called";
}
Demo(int x)
{
i = x;
cout<<"\nParameter contructor called";
}
void Display()
{
cout<<endl<<"i = "<<i<<endl;
}
};
int main()
{
Demo *demo = new Demo[5]; // = {1,2,3,4,5};
int i;
cout<<endl<<endl<<"First time";
cout<<endl<<"Addresses are "<<endl;
for( i=0;i<5; i++)
{
cout<<endl<< &demo[i];
}
cout<<endl<<endl<<"first time assigning values";
for( i=0;i<5; i++)
{
demo[i]= i;
}
cout<<endl<<endl<<"\nAfter first assignment";
cout<<endl<<"Addresses are "<<endl;
for( i=0;i<5; i++)
{
cout<<endl<< &demo[i];
}
cout<<endl<<endl<<"Second time assigning values";
for( i=0;i<5; i++)
{
demo[i]= i+5;
}
cout<<endl<<endl<<" After Second assignment ";
cout<<endl<<"Addresses are "<<endl;
for( i=0;i<5; i++)
{
cout<<endl<< &demo[i];
}
for( i=0;i<5; i++)
{
demo[i].Display();
}
return 0;
}
Output:
Default contructor called
Default contructor called
Default contructor called
Default contructor called
Default contructor called
First time
Addresses are
0x8281008
0x828100c
0x8281010
0x8281014
0x8281018
first time assigning values
Parameter contructor called
Parameter contructor called
Parameter contructor called
Parameter contructor called
Parameter contructor called
After first assignment
Addresses are
0x8281008
0x828100c
0x8281010
0x8281014
0x8281018
Second time assigning values
Parameter contructor called
Parameter contructor called
Parameter contructor called
Parameter contructor called
Parameter contructor called
After Second assignment
Addresses are
0x8281008
0x828100c
0x8281010
0x8281014
0x8281018
i = 5
i = 6
i = 7
i = 8
i = 9
Here the constructor is called three time and the memory address are same, means it is not allocating new memory and uses the same address. Why?
Why is the constructor called more than one time?
When you do this:
demo[i]= i;
i is used to construct a temporary object using the constructor which takes an int. This temporary is then assigned to demo[i]. The assignment does not result in demo[i] being reconstructed as a new object with a different address (objects can't be reconstructed, and can never change their address), it simply results in a memberwise assignment from the members of the temporary to the members of demo[i] (unless you provide an assignment operator which does something different, which you didn't).
Thinking the constructor allocates the memory for your object is a fundamental misunderstanding. When the constructor is called you already have the memory allocated, either on the stack or on the heap. The constructor only prepares this memory for using it afterwards.
However, the constructor is often responsible for allocating further memory for resources used by your object, i.e.
class Container
{
public:
Container()
: ptr_(new int[5])
{}
// ...
private:
int* ptr_;
}
I've got the following class holding 3 datatypes:
class CentralBank{
MaxHeap richestBanks;
HashTable banks;
AccountTree accounts;
public:
CentralBank(int numAccounts, Account* accounts, int numBanks, Bank* bankArr);
void AddAccount(Account account);
void RemoveAccount(int accountID);
void AddBank(Bank bank);
int GetAccountsNumber(int bankID);
void GetKRichestBanks(unsigned int K, Bank* banks);
int GetSumBalance (int low, int high);
};
Here's the constructor:
CentralBank::CentralBank(int numAccounts, Account* accounts, int numBanks,
Bank* bankArr): accounts(numAccounts,accounts){
int** locs = new int*[numBanks];
richestBanks = MaxHeap(numBanks,bankArr, locs);
banks = HashTable(numBanks,bankArr,locs);
delete[] locs;
}
My problem is that the destructor for the heap and the hash table is called right after their constructor. If I make both of them into pointers it doesn't happen.
Why does this happen?
Is there a way for them not to be pointers and not have the destructors called right after initialization? Am I not initializing them correctly?
PS: They aren't in the initialization list because their constructors need the "locs" parameter which needs to be initialized.
Once you enter the body of a constructor, the rules of C++ guarantee that all base classes of the class and all members of the class have been initialized. That's why the initialization list is outside of the constructor's body; because it gets called before your constructor body. If you didn't specify a constructor and parameters in your constructor's initialization list, then it will be default initialized.
So richestBanks and banks have already been initialized at this point. And you can't initialize an object twice.
richestBanks = MaxHeap(numBanks,bankArr, locs);
What this does is create a new MaxHeap object temporary, then call the copy assignment operator (or move assignment, where appropriate) to copy the new data into richestBanks. After which point, the temporary object must be destroyed. That's the destructor call you're seeing.
The correct solution is to stop doing whatever you need locs for and find a better way to construct your data, so that you can properly use the initialization list.
richestBanks = MaxHeap(numBanks,bankArr, locs)
As I remember, this means, that you create a temporary object, run copy constructor to copy it to the richestBanks variable, and then destruct this temp var.
The better solution is to have a reference to the object (MaxHeap&) instead the object itself, or a pointer.
My problem is that the destructor for the heap and the hash table is called right after their constructor.
The destructors are being called for the temporary instances of MaxHeap and HashTable constructed in the body of the CentralBank constructor, which go out of scope at the end. These temporaries are copied into the member variables richestBanks and banks, which were already initialized on entry into the body of this constructor.
Assuming you really need the array of int pointers, you can set up an auxiliary class to deal with its lifetime according to normal RAII guidelines. Something like this:
class IntPointerArray
{
public:
IntPointerArray( int num )
: array_(new int*[num])
{}
~IntPointerArray()
{ delete [] array_; }
operator int** ()
{ return array_; }
private:
int** array_;
};
Now, extending your class to hold an instance of this as a member:
class CentralBank{
IntPointerArray locs;
MaxHeap richestBanks;
HashTable banks;
AccountTree accounts;
// rest omitted
And observing the rule that members are initialized in the order of their declarations, your constructor can now look like this:
CentralBank::CentralBank(int numAccounts, Account* accounts, int numBanks, Bank* bankArr)
: locs(numBanks)
, richestBanks(numBanks,bankArr, locs) // exploits operator int**
, banks(numBanks,bankArr, locs) // ditto
, accounts(numAccounts,accounts)
{}
This way, all members are initialized directly, and no constructor body with temporaries is needed at all.
Whether you should be using an external array like this is worth looking into also. I'm guessing you really need the data structure known as a treap.
What EXACTLY is the difference between INITIALIZATION and ASSIGNMENT ?
PS : If possible please give examples in C and C++ , specifically .
Actually , I was confused by these statements ...
C++ provides another way of initializing member variables that allows us to initialize member variables when they are created rather than afterwards. This is done through use of an initialization list.
Using an initialization list is very similar to doing implicit assignments.
Oh my. Initialization and assignment. Well, that's confusion for sure!
To initialize is to make ready for use. And when we're talking about a variable, that means giving the variable a first, useful value. And one way to do that is by using an assignment.
So it's pretty subtle: assignment is one way to do initialization.
Assignment works well for initializing e.g. an int, but it doesn't work well for initializing e.g. a std::string. Why? Because the std::string object contains at least one pointer to dynamically allocated memory, and
if the object has not yet been initialized, that pointer needs to be set to point at a properly allocated buffer (block of memory to hold the string contents), but
if the object has already been initialized, then an assignment may have to deallocate the old buffer and allocate a new one.
So the std::string object's assignment operator evidently has to behave in two different ways, depending on whether the object has already been initialized or not!
Of course it doesn't behave in two different ways. Instead, for a std::string object the initialization is taken care of by a constructor. You can say that a constructor's job is to take the area of memory that will represent the object, and change the arbitrary bits there to something suitable for the object type, something that represents a valid object state.
That initialization from raw memory should ideally be done once for each object, before any other operations on the object.
And the C++ rules effectively guarantee that. At least as long as you don't use very low level facilities. One might call that the C++ construction guarantee.
So, this means that when you do
std::string s( "one" );
then you're doing simple construction from raw memory, but when you do
std::string s;
s = "two";
then you're first constructing s (with an object state representing an empty string), and then assigning to this already initialized s.
And that, finally, allows me to answer your question. From the point of view of language independent programming the first useful value is presumably the one that's assigned, and so in this view one thinks of the assignment as initialization. Yet, at the C++ technical level initialization has already been done, by a call of std::string's default constructor, so at this level one thinks of the declaration as initialization, and the assignment as just a later change of value.
So, especially the term "initialization" depends on the context!
Simply apply some common sense to sort out what Someone Else probably means.
Cheers & hth.,
In the simplest of terms:
int a = 0; // initialization of a to 0
a = 1; // assignment of a to 1
For built in types its relatively straight forward. For user defined types it can get more complex. Have a look at this article.
For instance:
class A
{
public:
A() : val_(0) // initializer list, initializes val_
{}
A(const int v) : val_(v) // initializes val_
{}
A(const A& rhs) : val_(rhs.val_) // still initialization of val_
{}
private:
int val_;
};
// all initialization:
A a;
A a2(4);
A a3(a2);
a = a3; // assignment
Initialization is creating an instance(of type) with certain value.
int i = 0;
Assignment is to give value to an already created instance(of type).
int i;
i = 0
To Answer your edited Question:
What is the difference between Initializing And Assignment inside constructor? &
What is the advantage?
There is a difference between Initializing a member using initializer list and assigning it an value inside the constructor body.
When you initialize fields via initializer list the constructors will be called once.
If you use the assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
For an integer data type or POD class members there is no practical overhead.
An Code Example:
class Myclass
{
public:
Myclass (unsigned int param) : param_ (param)
{
}
unsigned int param () const
{
return param_;
}
private:
unsigned int param_;
};
In the above example:
Myclass (unsigned int param) : param_ (param)
This construct is called a Member Initializer List in C++.
It initializes a member param_ to a value param.
When do you HAVE TO use member Initializer list?
You will have(rather forced) to use a Member Initializer list if:
Your class has a reference member
Your class has a const member or
Your class doesn't have a default constructor
Initialisation: giving an object an initial value:
int a(0);
int b = 2;
int c = a;
int d(c);
std::vector<int> e;
Assignment: assigning a new value to an object:
a = b;
b = 5;
c = a;
d = 2;
In C the general syntax for initialization is with {}:
struct toto { unsigned a; double c[2] };
struct toto T = { 3, { 4.5, 3.1 } };
struct toto S = { .c = { [1] = 7.0 }, .a = 32 };
The one for S is called "designated initializers" and is only available from C99 onward.
Fields that are omitted are automatically initialized with the
correct 0 for the corresponding type.
this syntax applies even to basic data types like double r = { 1.0
};
There is a catchall initializer that sets all fields to 0, namely { 0 }.
if the variable is of static linkage all expressions of the
initializer must be constant expressions
This {} syntax can not be used directly for assignment, but in C99 you can use compound literals instead like
S = (struct toto){ .c = { [1] = 5.0 } };
So by first creating a temporary object on the RHS and assigning this to your object.
One thing that nobody has yet mentioned is the difference between initialisation and assignment of class fields in the constructor.
Let us consider the class:
class Thing
{
int num;
char c;
public:
Thing();
};
Thing::Thing()
: num(5)
{
c = 'a';
}
What we have here is a constructor that initialises Thing::num to the value of 5, and assigns 'a' to Thing::c. In this case the difference is minor, but as was said before if you were to substitute int and char in this example for some arbitrary classes, we would be talking about the difference between calling a parameterised constructor versus a default constructor followed by operator= function.
Why do I have to provide default ctor if I want to create an array of objects of my type?
Thanks for answers
Because they have to be initialized.
Consider if it wasn't the case:
struct foo
{
foo(int) {}
void bar(void) {}
};
foo a[10];
foo f = a[0]; // not default-constructed == not initialized == undefined behavior
Note you don't have to:
int main(){
// initializes with the int constructor
foo a[] = {1, 2, 3};
}
// if the constructor had been explicit
int main(){
// requires copy-constructor
foo a[] = {foo(1), foo(2), foo(3)};
}
If you really need an array of objects and you can't give a meaningful default constructor, use std::vector.
If you really need an array of of objects, can't give a meaningful default constructor, and want to stay on the stack, you need to lazily initialize the objects. I have written such a utility class. (You would use the second version, the first uses dynamic memory allocation.)
For example:
typedef lazy_object_stack<foo> lazy_foo;
lazy_foo a[10]; // 10 lazy foo's
for (size_t i = 0; i < 10; ++i)
{
// create a foo, on the stack, passing `i` to the constructor
a[i].create(i);
}
for (size_t i = 0; i < 10; ++i)
a[i].get().bar(); // and use it
// automatically destructed, of course
The default constructor will be called for each object in the array.
You don't have to specify a default constructor as one will be created for you.
Just make sure you don't declare a constructor with no parameters as private or protected.
Here's an example of one being created for you:
class C
{
};
C c[10];
Whereas if you make it private you get a compiling error:
class C
{
private:
C()
{
}
};
C c[10];
When defining an array, you cannot specify ctor parameter, hence every object in the array must be constructed using the default ctor.
Normally, the C++ compiler will create the default ctor for you automatically. But, if you define a ctor with parameters, then the automatically creation of the default ctor is supressed, and you must explicitly write one.
Because when the array is initialized, default constructors are called for its items.