To understand working of constructor, copy constructor, destructor, I wrote the following code.
#include <iostream>
using namespace std;
class Cat
{
public:
Cat();
Cat(Cat&);
~Cat();
int itsage;
};
Cat::Cat()
{
cout << "Constructor called\n";
cout << this << endl;
itsage=2;
}
Cat::Cat(Cat& theCat)
{
cout << "Copy constructor called\n";
cout << this << endl;
itsage=theCat.itsage;
}
Cat::~Cat()
{
cout << "Destructor called\n";
cout << this << endl;
}
Cat myFunction(Cat Frisky)
{
cout << "Inside myFunction\n";
cout << "Frisky's address : " << &Frisky ;
cout << "\nFrisky's age: " << Frisky.itsage << "\n";
Frisky.itsage=100;
cout << "Reassigned Frisky's age: "<< Frisky.itsage << "\n";
return Frisky;
}
int main()
{
Cat Mani;
cout << "Mani's address : " << &Mani ;
cout << "\nMani's age: " << Mani.itsage << "\n";
myFunction(Mani);
return 0;
}
I got output as follows:
Constructor called
0x61ff04
Mani's address : 0x61ff04
Mani's age: 2
Copy constructor called
0x61ff0c
Inside myFunction
Frisky's address : 0x61ff0c
Frisky's age: 2
Reassigned Frisky's age: 100
Copy constructor called
0x61ff08
Destructor called
0x61ff08
Destructor called
0x61ff0c
Destructor called
0x61ff04
Everything is ok to me except what is stored at address 0x61ff08 when there was second call to copy constructor? Means we can see what is stored at addresses 0x61ff0c and 0x61ff04 which are nothing but Frisky and Mani. Then what is that invisible thing at 0x61ff08?
I thought of making that object visible by making a small change in main function.
#include <iostream>
using namespace std;
class Cat
{
public:
Cat();
Cat(Cat&);
~Cat();
int itsage;
};
Cat::Cat()
{
cout << "Constructor called\n";
cout << this << endl;
itsage=2;
}
Cat::Cat(Cat& theCat)
{
cout << "Copy constructor called\n";
cout << this << endl;
itsage=theCat.itsage;
}
Cat::~Cat()
{
cout << "Destructor called\n";
cout << this << endl;
}
Cat myFunction(Cat Frisky)
{
cout << "Inside myFunction\n";
cout << "Frisky's address : " << &Frisky ;
cout << "\nFrisky's age: " << Frisky.itsage << "\n";
Frisky.itsage=100;
cout << "Reassigned Frisky's age: "<< Frisky.itsage << "\n";
return Frisky;
}
int main()
{
Cat Mani;
cout << "Mani's address : " << &Mani ;
cout << "\nMani's age: " << Mani.itsage << "\n";
Cat Sweety = myFunction(Mani);
cout << "Sweety's age : " << Sweety.itsage ;
return 0;
}
But received an error as follows :
ppp.cpp: In function 'int main()':
ppp.cpp:47:25: error: invalid initialization of non-const reference of type 'Cat&' from an rvalue of type 'Cat'
Cat Sweety = myFunction(Mani);
~~~~~~~~~~^~~~~~
ppp.cpp:19:2: note: initializing argument 1 of 'Cat::Cat(Cat&)'
Cat::Cat(Cat& theCat)
^~~
I really didn't get what went wrong.
Your first code returns a copy of Frisky from myFunction, that is where the additional copy comes from.
Your second code doesn't work because your copy constructor erroneously takes a non-const reference and you can't pass the temporary value returned from myFunction to a non-const reference.
Not directly related to your question but you should obey the rule of three and implement the assignment operator too.
Cat(Cat &);
Use const here.
Cat(const Cat &);
Not related but consider using initialisation like this.
Cat Sweety{myFunction(Mani)};
Related
I'm adapting to an interface with parameter const vector<pair<int32_t, A>>& as.
To avoid multi-construct and multi-destruct, I write CreateAs as follow.
I was expecting it to trigger create move del each for once, but it turned out triggered move and del for twice.
What's the reason?
I made this way so that the A objects could destroy themselves automatically, even with new but without delete. Am I doing it right?
To reproduce it: https://repl.it/#unix1/ShrillFirsthandAdvance
#include <iostream>
#include <vector>
using namespace std;
struct A {
A() { cout << "A()" << endl; }
A(int32_t a) : a_(a) { cout << "Create A: " << a << endl; }
A(const A& oa) { a_ = oa.a_; cout << "Copy A: " << oa.a_ << endl; }
A(A& oa) { a_ = oa.a_; cout << "Copy A non-const: " << oa.a_ << endl; }
A(const A&& oa) { a_ = oa.a_; cout << "Move A: " << oa.a_ << endl; }
A(A&& oa) { a_ = oa.a_; cout << "Move A non-const: " << oa.a_ << endl; }
~A() { cout << "Del A: " << a_ << ", ptr: " << this << endl; }
int32_t a_;
};
void CreateAs(vector<pair<int32_t, A>>& as) {
as.reserve(3);
for (int32_t i = 0; i < 3; ++i) {
A* a = new A(i*i);
cout << "a ptr: " << &a << endl;
cout << "-----before insert----" << endl;
as.emplace_back(make_pair(i, move(*a)));
cout << "-----after insert-----" << endl;
}
}
void Test() {
vector<pair<int32_t, A>> as;
cout << "-----Create begin----" << endl;
CreateAs(as);
cout << "-----Create end------" << endl;
for (const auto& item : as) {
cout << item.first << "->" << item.second.a_ << endl;
}
}
int main(int32_t argc, char* argv[]) {
Test();
cout << "____end test____" << endl;
return 0;
}
make_pair constructs an A in a pair. emplace_back moves the pair and therefore A into the vector. The moved from pair is destroyed, also destroying the contained A.
To avoid any move, you might do
void CreateAs(std::vector<std::pair<int32_t, A>>& as) {
as.reserve(3);
for (int32_t i = 0; i < 3; ++i) {
as.emplace_back(i, i*i);
}
}
Demo
You currently have extra move with your extra make_pair.
I would like to count the number of objects that my program creates over its lifetime. Based on the solution provided here:
how to count the number of objects created in c++
I have the following code:
#include <iostream>
using namespace::std;
using std::cout;
using std::endl;
template <typename T>
struct counter
{
counter()
{
objects_created++;
objects_alive++;
}
virtual ~counter()
{
--objects_alive;
}
static int objects_created;
static int objects_alive;
};
template <typename T> int counter<T>::objects_created(0);
template <typename T> int counter<T>::objects_alive(0);
class X : counter<X>
{
int a;
};
class Y : counter<Y>
{
int b;
};
void fooX(class X x) {
cout << "passing object" << endl;
}
void fooY(class Y& y) {
cout << "passing reference" << endl;
}
int main()
{
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
X x;
Y y;
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
fooX(x);
fooY(y);
cout << "created: " << " X:" << counter<X>::objects_created << " Y:" << counter<Y>::objects_created << endl;
cout << "alive: " << " X:" << counter<X>::objects_alive << " Y:" << counter<Y>::objects_alive << endl;
int ui;
cin >> ui;
}
I expected that since x is passed by value, a copy of it is made inside fooX making the total number of objects of class X to be 2 while since y is passed by reference, the total number of objects of class Y to be 1.
Yet, the output of the code is as follows:
created: X:0 Y:0
alive: X:0 Y:0
created: X:1 Y:1
alive: X:1 Y:1
passing object
passing reference
created: X:1 Y:1
alive: X:0 Y:1
Why does not the number of Xs created be 2?
A copy constructor is automatically added to your counter class, and that automatically created copy constructor doesn't increment your static variables.
Write a copy constructor which does that:
counter(counter const&)
{
objects_created++;
objects_alive++;
}
Note that your destructor should probably not be virtual, unless you intend to delete dynamically created instances of derived classes via pointers or references to counter. As it stands, it's just premature pessimisation because it needlessly increases the size of your objects.
I'm trying to execute the following code:
#include <iostream>
using namespace std;
class ABC {
private:
int x, y;
public:
ABC(){
cout << "Default constructor called!" << endl;
ABC(2, 3);
cout << x << " " << y << endl;
}
ABC(int i, int j){
cout << "Parameterized constructor called with parameters "<< i << " " << j << "!" << endl;
x = i;
y = j;
cout << x << " " << y << endl;
}
};
int main(){
ABC a;
return 0;
}
I am getting the following output:
Default constructor called!
Parameterized constructor called with parameters 2 3!
2 3
-858993460 -858993460
Shouldn't the member variables be initialized with values 2 and 3?
ABC(2, 3); doesn't call the constructor to initialize the members, it just create a temporary variable which will be destroyed immediately.
If you meant delegating constructor you should:
ABC() : ABC(2, 3) {
cout << "Default constructor called!" << endl;
cout << x << " " << y << endl;
}
Note this is a C++11 feature. You can add a member function if you can't use C++11.
class ABC {
private:
int x, y;
init(int i, int j) {
x = i;
y = j;
}
public:
ABC(){
cout << "Default constructor called!" << endl;
init(2, 3);
cout << x << " " << y << endl;
}
ABC(int i, int j){
cout << "Parameterized constructor called with parameters "<< i << " " << j << "!" << endl;
init(i, j);
cout << x << " " << y << endl;
}
};
You create a temporary variable in ABC() body. You can use this syntax to overcome this:
class ABC
{
private:
int x, y;
public:
ABC() : ABC(2,3)
{
std::cout << "Default constructor called!" << std::endl;
}
ABC(int i, int j)
{
std::cout << "Parameterized constructor called with parameters "<< i << " " << j << "!" << std::endl;
x = i;
y = j;
std::cout << x << " " << y << std::endl;
}
};
I am learning C++ as a hobby and am wrestling with using "new" to dynamically create a class object. I have read that dynamically created classes do not lose scope, but that does not seem to work for my simple example.
When executed, the value of 'testValue1' is set to 555 in the constructor and printed. When the control is returned to main, 'testvalue' is unfortunately set to 0 (or not defined--not sure). I can set the value inside of main and the value is properly maintained inside of main as well as in a for loop.
The problem: I don't understand why the initialized value of 555 is not maintained when control is returned to main. I know I am doing something wrong or not understanding scope for dynamically assigned class object properly...any assistance is appreciated. Here is the sample code:
//main.cpp
#include <iostream>
using namespace std;
class generalVars
{
private:
public:
//data attributes
int testValue1;
//constructor
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555;
cout << "testValue1 has been set " << testValue1 << endl;
}
~generalVars(void)
{
cout << "I am in general vars destructor" << endl;
};
};
int main(int argc, char *argv[])
{
cout << "I am in Main" << endl;
generalVars* myGeneralVars = new generalVars; //create on heap
cout << "Main1 testvalue1 = " << myGeneralVars->testValue1 << endl;
myGeneralVars->testValue1 = 777;
cout << "Main2 testvalue1 = " << myGeneralVars->testValue1 << endl;
for (int i=0; i<= 3; i++)
{
cout << "Inside while loop..." << endl;
cout << "Main3 " << i << " testvalue1 = " << myGeneralVars->testValue1 << endl;
}
delete myGeneralVars; //delete from heap
return 0;
}
This statement:
int testValue1= 555;
declares a local variable, distinct from the data member of the same name.
So it doesn't change the value of the member.
Instead, do e.g.
testValue1= 555;
Or use the constructor's memory initializer list, like this:
generalVars()
: testValue1( 555 )
{
cout << "I am in general vars constructor" << endl;
cout << "testValue1 has been set " << testValue1 << endl;
}
You defined another variable in generalVars constructor and init value to 555, to init member testValue1, you don't need to define it again in constructor.
update
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555; // this defines another testValue1 variable. it's different from member testValue1
cout << "testValue1 has been set " << testValue1 << endl;
}
to
generalVars()
{
cout << "I am in general vars constructor" << endl;
testValue1= 555; // Note, removed int
cout << "testValue1 has been set " << testValue1 << endl;
}
Two things are going on:
1) you re-declare testValue1 here by putting int in front:
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555; //right here!
cout << "testValue1 has been set " << testValue1 << endl;
}
This hides the class's own instance of testValue1 with a new unique variable by the same name. You can reference both like so:
generalVars()
{
cout << "I am in general vars constructor" << endl;
int testValue1= 555; //note, still has int
cout << "testValue1 has been set " << testValue1 << endl;
cout << "this->testValue1 has not been set and is " << this->testValue1 << endl;
this->testValue1 = 555; //note, this->
cout << "this->testValue1 has been set " << this->testValue1<< endl;
}
Or you could avoid the name clash and refer to it normally:
generalVars()
{
cout << "I am in general vars constructor" << endl;
testValue1= 555; //note, no int. This is identical to this->testValue1
cout << "testValue1 has been set " << testValue1 << endl;
}
Next is not really an issue, but should be noted:
You do not need to heap allocate things with new in C++ most of the time. You should prefer stack allocated objects
generalVars myObject;
instead of:
generalVars *myObject = new generalVars();
...
delete myObject;
Or, in cases where you do want to create a heap allocated object:
auto myObject = std::make_unique<generalVars>();
Or, if you need multiple handles:
auto myObject = std::make_shared<generalVars>();
The unique_ptr and shared_ptr examples do not require explicit deletion. The heap allocation will be deleted when the pointer object goes out of scope. This especially helps with exception safety.
I have just recently started class inheritance in c++. While I was making a "Test" program, a error occurred with the cout statement. No clue how to fix it and would be appreciate your response.
#include <iostream>
using namespace std;
class Power{
public:
void isWeak(){
cout << " Weak"<< endl;
}
void isStrong(){
cout << " Strong" << endl;
}
};
class Person:public Power{};
class Person2:public Power{};
int main(){
Person human;
Person2 human2;
cout << "Human is " << human.isWeak() << endl; //error
cout << "Human 2 is " << human2.isStrong() << endl; //error
system("pause");
return 0;
}
the main()'s cout statement has that error between the output and human
Change the functions to
char const *isWeak(){
return " Weak";
}
char const *isStrong(){
return " Strong";
}
As currently defined, both functions have void return type, which means the cout statements within main are trying to print void, which doesn't make sense, and is the cause of the error.
You are attempting to print a void:
cout << "Human is " << human.isWeak() << endl;
is the same as typing
cout << "Human is " << void << endl;
Which will not compile. What you need to do is define your functions in either of the following ways:
class Power
{
public:
std::string isWeak()
{
return std::string(" is weak");
}
std::string isStrong()
{
return std::string(" is strong");
}
};
Or, change your code:
cout << "Human is ";
human.isWeak();
cout << endl;
cout << "Human 2 is ";
human2.isStrong();
cout << endl;
Problem is with isWeak() and isStrong() return type. these two functions return void and you are trying to print it. you can try this-
cout << "Human is " ;
human.isWeak();
cout << endl;
cout << "Human 2 is " ;
human2.isStrong();
cout << endl;
You're trying to 'print' a 'void' statement in cout << "Human is " << human.isWeak() << endl;
You'll need to change your isWeak and isStrong functions to return a std::string/const char* or change the way you call them:
to string:
const char* isWeak() {
return " Weak";
}
// then you can do
cout << "Human is " << human.isWeak() << endl;
Or change the way you call the function:
cout << "Human is ";
human.isWeak();
Your isWeak and isStrong functions are void they do not return anything; calling cout << human.isWeak() is expecting isWeak to return something (an int, string, double, etc.).