confusion regarding the copy constructor calling - c++

I found this code on the internet. I am a bit confused about the calling of the copy constructor and I just wanted to know why the copy constructor is called when the display function is called?
#include<iostream>
using namespace std;
class myclass
{
int val;
int copynumber;
public:
//normal constructor
myclass(int i)
{
val = i;
copynumber = 0;
cout<<"inside normal constructor"<<endl;
}
//copy constructor
myclass (const myclass &o)
{
val = o.val;
copynumber = o.copynumber + 1;
cout<<"Inside copy constructor"<<endl;
}
~myclass()
{
if(copynumber == 0)
cout<<"Destructing original"<<endl;
else
cout<<"Destructing copy number"<<endl;
}
int getval()
{
return val;
}
};
void display (myclass ob)
{
cout<<ob.getval()<<endl;
}
int main()
{
myclass a(10);
display (a);
return 0;
}

In the display method you are passing the parameter by value, so obviously there will be a copy made and sent to the function. Learn the difference of pass by value and reference. this and this tutorials may be useful.

It is being invoked because you are passing the object value rather than by const reference. If you passed a const myclass& ob, instead, then the copy constructor wouldn't get called. However, as is, your function is set up to create a copy of the parameter (that is, your function operates on a copy, not the original object).

Related

Declaring and Assigning a object some rvalue in the same line

I am trying to replicate the string class function where we can declare and assign a string class object value some rvalue in the same line.
e.g string s1 = "Hello"
But I am trying to do it with integers. My code is like this.
#include <iostream>
using namespace std;
class Foo {
private:
int a;
public:
Foo () {
}
explicit Foo(int a) {
this->a = a;
}
Foo(Foo &obj) {
this->a = obj.a;
}
void operator= (int a) {
cout<<"operator called "<<endl;
this->a=a;
}
void print() {
cout<<"a is "<<this->a<<endl;
}
};
int main () {
Foo obj2 = 10; // Getting error here (no int to Foo conversion found)
obj2.print();
return 0;
}
I understand that removing explicit from my single parameter constructor (i.e making it a converting constructor) would do the trick but I want to keep the ctor as explicit. Is there any way to achieve this? I tried to overload the "=" assignment operator as well but no luck. Please help.
Main purpose of declaring constructor explicit, according to Bjarne, is to make implicit conversion illegal, e.g.
void Bar(Foo a);
Foo obj2 = 10; // illegal, conversion int to Foo
Bar(10); // illegal too
Instead those should be converted explicitly:
Foo obj2 = Foo(10);
Bar(Foo(10));

Copy struct to array with const values

I'm trying to replace a struct value that has a const value in a non const array but it fails to compile with:
Object of type 'Foo' cannot be assigned because its copy assignment operator is implicitly deleted
Here is an example:
struct Foo {
const int id;
int value;
Foo(): id(-1), value(-1) {}
Foo(int id): id(id), value(0) {}
};
int main(int argc, const char * argv[]) {
Foo foos[10];
foos[0] = Foo(1234);
return 0;
}
I'm coming from a swift background where that is valid as it copies the struct value into the array.
I tried making what I thought was a copy assignment operator but with const members what I tried didn't work either.
This is what I was trying to do for the copy assignment operator:
Foo& operator= (Foo newVal) {
// what do I put here!?
return *this;
};
Doing a memcpy to the array works but seems like the wrong sledgehammer for the job.
Being new at c++ I'm unsure what the correct pattern is for this type of flow.
C++ treats const very strictly. Copying such a struct will be painful if possible at all (without UB). Perhaps what you are really looking for is "readonly" instead? In that case you can make fields private with public getters/setters:
struct Foo {
public:
Foo(): id(-1), value(-1) {}
Foo(int id): id(id), value(0) {}
int getId() const {
return id;
}
int getValue() const {
return value;
}
void setValue(int newValue) {
value = newValue;
}
private:
int id;
int value;
};
You can never change a const value after it's been initialized.
From the name id it sounds like move semantics is what you need. Instead of having two valid objects with the same id, you can make it possible to move the data between objects, but not to copy it.
Example:
#include <iostream>
#include <utility>
struct Foo {
Foo() : id(-1), value(-1) {} // default - "invalid" values
Foo(int id, int value) : id(id), value(value) {} // constructor
explicit Foo(int id) : Foo(id, 0) {} // converting ctor, delegating
Foo(const Foo&) = delete; // no copy construction
Foo(Foo&& rhs) : // move construction ok
id(std::exchange(rhs.id, -1)), // take id, give -1 back
value(std::exchange(rhs.value, -1)) // take value, give -1 back
{}
Foo& operator=(const Foo&) = delete; // no copy assignment
Foo& operator=(Foo&& rhs) { // move assignment ok
// give the "moved from" element our id and value and
// take id and value from the "moved from" element
std::swap(id, rhs.id);
std::swap(value, rhs.value);
return *this;
}
int Id() const { return id; } // only const access
int& Value() { return value; } // non-const access in non-const context
int Value() const { return value; } // const access in const context
private:
int id;
int value;
};
int main() {
Foo foos[2];
foos[0] = Foo(1234); // The temporary Foo will have (-1, -1) when it's destroyed
for(auto& f : foos)
std::cout << f.Id() << ' ' << f.Value() << '\n';
}
Output:
1234 0
-1 -1
In C++, an object can be initialized only once. Your constant member is initialized via the default constructor when you declare the array. Then, you attempt to change that value via assignment
foos[0] = Foo(1234);
This fails, and righly so. One thing you could do is to have a container of not Foos, but some sort of pointers to foo. Thus, you will have allocated the memory for the pointers but will create the actual objects only when you can. For example:
Foo* foos[10]; //here you have only the pointers
foos[0] = new Foo(1234); //OK, the object is inialized here
You may consider using smart pointers such as std::unique_ptr instead of raw pointers here.
Times, and C++ standards have changed!
You can now define your own copy-assignment operator for classes that contain const member objects without undefined behavior as of c++20.
This was undefined behavior prior to c++ and remains so for complete const objects but not non-const objects with const members.
https://stackoverflow.com/a/71848927/5282154

Why Copy Constructor not called?

I have the following piece of code:
#include<iostream>
using namespace std;
class A{
int size;
double *arr;
public:
A(int len):size(len)
{
cout<<"ctor called"<<endl;
arr=new double[size];
}
A(const A &rhs)
{
cout<<"calling copy ctor"<<endl;
size=rhs.size;
arr=new double[size];
}
~A()
{
cout<<"calling dtor"<<endl;
delete[] arr;
arr=NULL;
size=0;
}
};
A createVector()
{
cout<<"Creating object"<<endl;
A a(10);
cout<<"returning after creating object a"<<endl;
return a;
}
void foo(A v)
{
cout<<"Class A object rcvd"<<endl;
//return v;
}
int main()
{
A a=createVector();
cout<<"a has been rcvd"<<endl;
foo(a);
return 0;
}
And I have the following output:
Creating object
ctor called
returning after creating object a
a has been rcvd
calling copy ctor
Class A object rcvd
calling dtor
calling dtor
I am having trouble with createVector() function. When I return a object by value,its copy constructor should be called but I am not seeing any output between the lines
returning after creating object a
a has been rcvd
Why copy constructor has not been called??
(when I pass the rcvd object as value to foo(),Copy Constructor gets called)

Assigning object after operation via operator

I want to add contents of two classes and save them in another class. I have created constructor, parameterized constructor, destructor and overloaded = parameter. It is working fine for Demo b = a; but when I try to save the object given by a.addition(b), there's error no viable overloaded '='. My concept is why the object is not getting copied to newly created object?
Class Demo
class Demo
{
int* ptr;
public:
Demo(int data = 0) {
this->ptr = new int(data);
}
~Demo(void) {
delete this->ptr;
}
// Copy controctor
Demo(Demo &x) {
ptr = new int;
*ptr = *(x.ptr);
}
void setData(int data) {
*(this->ptr) = data;
}
int getData() {
return *(this->ptr);
}
Demo operator = (Demo& obj) {
Demo result;
obj.setData(this->getData());
return result;
}
Demo addition(Demo& d) {
Demo result;
cout << "result: " << &result << endl;
int a = this->getData() + d.getData();
result.setData(a);
return result;
}
};
Main
int main(void)
{
Demo a(10);
Demo b = a;
Demo c;
c = a.addition(b); // error here
return 0;
}
The operator= takes a referecne to non-const (i.e. Demo&) as its parameter, which can't bind to the temporary object returned by addition.
To solve the issue you should change the parameter type to reference to const (i.e. const Demo&), which could bind to temporary and is conventional.
BTW: The target and source of the assignment seem to be opposite. I suppose it should be implemented as
Demo& operator= (const Demo& obj) {
setData(obj.getData());
return *this;
}
And declare getData as a const member function.

c++ copy assignment operator for reference object variable

I give the following example to illustrate my question:
class Abc
{
public:
int a;
int b;
int c;
};
class Def
{
public:
const Abc& abc_;
Def(const Abc& abc):abc_(abc) { }
Def& operator = (const Def& obj)
{
// this->abc_(obj.abc_);
// this->abc_ = obj.abc_;
}
};
Here I do not know how to define the copy assignment operator. Do you have any ideas? Thanks.
references cannot be assigned to. You need something that can. A pointer would work, but they're very abusable.
How about std::reference_wrapper?
#include <functional>
class Abc
{
public:
int a;
int b;
int c;
};
class Def
{
public:
std::reference_wrapper<const Abc> abc_;
Def(const Abc& abc):abc_(abc) { }
// rule of zero now supplies copy/moves for us
// use the reference
Abc const& get_abc() const {
return abc_.get();
}
};
A reference cannot be assigned. Due to this, one can only define it via placement new and copy construction:
Def& operator = (const Def& obj)
{
this->~Def(); // destroy
new (this) Def(obj); // copy construct in place
}
But it is really unnecesary. Just use a pointer.