Here is my code below:
template<class t>
class smart_ptr{
t *ptr;
public:
smart_ptr(t *p):ptr(p){cout<<"smart pointer copy constructor is called"<<endl;}
smart_ptr(const smart_ptr &sm){cout<<"copy constructor is called"
<<endl;ptr=sm->ptr;}
~smart_ptr(){cout<<"smart pointer destructor is called"<<endl;delete(ptr);}
t& operator *(){cout<<"returning the * of pointer"<<endl;return(*ptr);}
t* operator ->(){cout<<"returning the -> of pointer"<<endl;return(ptr);}
t& operator=(const t &lhs){ptr=lhs->ptr;cout<<"assignement operator called"
<<endl;return *this;}
};
class xxx{
int x;
public:
xxx(int y=0):x(y){cout<<"xxx constructor called"<<endl;}
~xxx(){cout<<"xxx destructor is called"<<endl;}
void show(){cout<<"the value of x="<<x<<endl;}
};
int main(int argc, char *argv[])
{
xxx *x1=new xxx(50);
smart_ptr<xxx> p2(new xxx(60));
smart_ptr<xxx> p1(x1);
p1->show();
smart_ptr<xxx> p3(p2); //calling copy construcotr is giving error
p3=p1; //calling assignment operator is giving error
p2->smart_ptr<class xxx>::~smart_ptr<class xxx>(); //calling smart pointer
destructor gives error
return 0;
}
I am getting compilation errors while compiling this file because of wrong copy constructor, assignment operator and destructor codes.
The errors are:
smart_pointer_impl.cpp: In function ‘int main(int, char**)’:
smart_pointer_impl.cpp:33: error: ‘smart_ptr<xxx>’ is not a base of ‘xxx’
smart_pointer_impl.cpp: In copy constructor ‘smart_ptr<t>::smart_ptr(const
smart_ptr<t>&) [with t = xxx]’:
smart_pointer_impl.cpp:28: instantiated from here
smart_pointer_impl.cpp:8: error: passing ‘const smart_ptr<xxx>’ as ‘this’ argument
of ‘t*
smart_ptr<t>::operator->() [with t = xxx]’ discards qualifiers
smart_pointer_impl.cpp:8: error: ‘class xxx’ has no member named ‘ptr’
Please find where I am wrong in the above functions. Any help is welcome.
One obvious error is that your assignment operator should take and return references to smart_ptr, not t:
smart_ptr& operator = (const smart_ptr& lhs)
//^^^^^^^^^ ^^^^^^^^^
Next, your copy constructor calls sm->ptr when it should be calling sm.ptr, since -> has been overloaded to return a t anyway:
smart_ptr(const smart_ptr& sm) : ptr(sm.ptr) { .... }
Compilation errors could be fixed with the following changes:
// copy ctor
smart_ptr(const smart_ptr &sm)
: ptr(sm.ptr)
{
cout<<"copy constructor is called" << endl;
}
// destructor's invocation
p2.~smart_ptr();
However there's a logic error in the copy constructor as the underlying object will be deleted twice (or more times).
Related
I am trying to write a move constructor for a structure but I can't understand why I fail to call the move constructor of structure member:
#include <memory>
struct C
{
std::unique_ptr<int[]> mVector;
size_t mSize;
C() = default;
C(C &&temp)
: mVector(temp.mVector)
, mSize(temp.mSize)
{}
};
When I compile this I get:
gcc -c TempTest.cpp
TempTest.cpp: In constructor 'C::C(C&&)':
TempTest.cpp:9:23: error: use of deleted function 'std::unique_ptr<_Tp [], _Dp>::unique_ptr(const std::unique_ptr<_Tp [], _Dp>&) [with _Tp = int; _Dp = std::default_delete<int []>]'
9 | , mSize(temp.mSize)
| ^
In file included from c:/msys64/mingw64/include/c++/10.3.0/memory:83,
from TempTest.cpp:1:
c:/msys64/mingw64/include/c++/10.3.0/bits/unique_ptr.h:723:7: note: declared here
723 | unique_ptr(const unique_ptr&) = delete;
| ^~~~~~~~~~
Because in contructor temp is a rvalue reference, it is non-const so temp.mVector should be non-const and should call the unique_ptr move constructor but instead it calls the copy constructor which is deleted. Any idea where is the error?
Why rvalue reference member would be const?
Don't assume that it's const. You should assume that unique_ptr(const unique_ptr&) is merely the best match, from the available constructors.
Because in constructor temp is a rvalue reference
Surprise! It is not an r-value reference.
The variable temp is bound to an r-value, when the constructor is called. And now that it's a named variable, it's no longer a "temporary". It has become an l-value.
Since you know that the value was an r-value when the constructor was called, you can safely move the members, converting them back to an r-value.
C(C &&temp)
: mVector(std::move(temp.mVector))
// ^^^^^^^^^ We know that temp CAME FROM an r-value,
// so it can safely be moved.
, mSize(temp.mSize)
{}
try to run the following code and everything become clear:
struct Test
{
Test(){}
Test(const Test& r)
{
std::cout << "i am using the copy constructor :) " << std::endl;
}
Test(Test&& r)
{
std::cout << "I require std::move to be selected as possible overload.." << std::endl;
}
};
int main()
{
Test first;
Test second(first);
Test third(std::move(second));
return 0;
}
std::move helps to select the right constructor overload by passing a r-value reference (Test&&) to the constructor.
In your case, the compiler is selecting the copy constructor even if your vector isn't const, just because it is considered the best match (an implicit cast to a const reference is preferred to an implicit cast to a r-value reference, since the second one, differently from the first, may modify the value) adding a std::move you can select the right constructor and solve your issue.
#include <memory>
struct C
{
std::unique_ptr<int[]> mVector;
size_t mSize;
C() = default;
C(C &&temp)
: mVector(std::move(temp.mVector))
, mSize(temp.mSize)
{}
};
Code:
class A
{
public:
A()
{
cout<<"Defualt Constructor"<<endl;
}
A(A &t)
{
cout<<"Copy Constructor"<<endl;
}
};
A func()
{
cout<<"In func"<<endl;
}
int main()
{
A a1;
A a2;
a2 = func();
return 0;
}
The program works fine. Also, If I call function like this:
A a2 = func();
and add const qualifier in copy constructor argument like:
A(const A &t)
{
cout<<"Copy Constructor"<<endl;
}
Also, working fine.
But, If remove const from copy constructor argument like:
A(A &t)
{
cout<<"Copy Constructor"<<endl;
}
and call function func()
A a2 = func();
Compiler giving an error:
error: invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A'
A a2 = func();
^
prog.cpp:13:9: note: initializing argument 1 of 'A::A(A&)'
A(A &t)
^
Why does compiler give an error in last case?
A a2 = func(); is copy initialization, a2 will be initialized from the object returned by func() via copy constructor. func() returns by value, so what it returns is a temporary, which can't be bound to lvalue-reference to non-const (i.e. A &), that's why you get the error.
Temporary could be bound to lvalue-reference to const (or rvalue-reference), so changing the parameter type to const A &t (or adding move constructor) would make it work fine.
BTW: a2 = func(); has nothing to do with copy constructor, but copy assignment operator. You didn't declare it for A, and the implicitly declared copy assignment operator takes const A& as parameter, then it's fine.
BTW2: func() returns nothing. Note that flowing off the end of a non-void function without returning leads to UB.
I have coded a very basic class
class A
{
int n;
public:
A(int& val){val=n;}
A(const int& val=0){n=val;}
A(A& val){n=val.n;}//work without this constructor
};
int main()
{
A a=3;//want to call A::A(const int&)
return 0;
}
I don't want to create a constructor with a copy from an instance of A (for a future use)
What's wrong with this simple code?
Error message :
...\main.cpp||In function 'int main()':|
...\main.cpp|16|error: no matching function for call to 'A::A(A)'|
...\main.cpp|16|note: candidates are:|
...\main.cpp|11|note: A::A(A&)|
...\main.cpp|11|note: no known conversion for argument 1 from 'A' to 'A&'|
...\main.cpp|10|note: A::A(const int&)|
...\main.cpp|10|note: no known conversion for argument 1 from 'A' to 'const int&'|
...\main.cpp|9|note: A::A(int&)|
...\main.cpp|9|note: no known conversion for argument 1 from 'A' to 'int&'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
It seems 3 is considered as an instance of A?
If I add A(const A& val){n=val.n;}
the constructor A(const int&) is chosen.
What can I do to compile successfully without A(const A& val)?
The issue is your copy constructor: A(A& val) { n=val.n; }.
Given this line A a = 3; one possibility is to use A a = A(3) which in turn will use the copy constructor. However, it is against the standard to bind a temporary to non-const. A proper copy constructor will solve the problem.
Example Code
#include <iostream>
class A
{
int n;
public:
A(int& val) : n(val) { std::cout << "A(int&)\n"; }
A(const int& val=0) : n(val) { std::cout << "A(const int&)\n"; }
A(const A& val) : n(val.n) { std::cout << "A(const A&)\n"; }
};
int main()
{
A a = 3;
return 0;
}
Example Output
A(const int&)
Live Example
Note:
The above code makes proper use of the initialization lists
The output shows the copy constructor is not actually invoked
The line of code;
A a = 3;
Is using copy initialisation to work. For that to work, a copy of A is needed and is duly made. You have two constructors taking an int as an argument (and neither are explicit).
The copy cannot bind to A(A& val) because normal references don't bind to temporary values.
Possible solutions, direct initialisation;
A a { 3 };
Add or change the copy constructor to a move constructor;
A(A&& val);
Add a const to the copy constructor (although this is not what you wanted, but it does work);
A(A const& val);
Note both clang and g++ reject the original code correctly, but VC++ accepts it.
In this statement
A a=3;//want to call A::A(const int&)
there is created a temporary object of type A using constructor
A(const int& val=0){n=val;}
However a temporary object can be bound to a constant reference. So the compiler need that the copy constructor
A( const A& val){n=val.n;}//work without this constructor
^^^^^
would be at least accessible (even if it will not be called due to the copy constructor elision).
But the class does not has this constructor and the compiler issues an error.
On the other hand when you comment this constructor then the compiler itself implicitly defines this constructor and the code is compiled.
Take into account that this constructor
A(int& val){val=n;}
^^^^^^
does not make sense.:)
Consider the following self contained Code.
#include <iostream>
template<typename Ty>
class Foo {
private:
Ty m_data;
public:
Foo() :m_data() {}
Foo(Ty data) :m_data(data) {}
template<typename U>
Foo& operator=(Foo<U> rv)
{
m_data = rv.m_data;
return *this;
}
private:
Foo(Foo&);
Foo& operator=(Foo&);
};
int main()
{
Foo<int> na(10);
Foo<int> nb;
nb = Foo<int>(10); // (1)
Foo<int>(10); // (2)
}
My understanding is statement (1) is an assignment rather than a Copy COnstructor. Yet, when compiling (VC++ and G++), the Error Message states, it tries to match a Copy Constructor which was declared private.
1>Source.cpp(23): error C2248: 'Foo<int>::Foo' : cannot access private member declared in class 'Foo<int>'
1> Source.cpp(16) : see declaration of 'Foo<int>::Foo'
My question is, why does it try to search for a Copy Constructor instead of an assignment.
Note, I know it is the assignment that is failing because (2) compiles fine without any error.
Your assignment operator takes its parameter by value, which requires making a copy. That copy may (or may not) be elided - but the copy constructor still needs to be available and accessible, even if not called.
There are two issues:
Your private assignment operator Foo& operator=(Foo&); takes a non-const lvalue reference. That means it cannot be selected as an overload in nb = Foo<int>(10);, because the RHS is an rvalue
That leads to your template assignment operator being selected. But that takes its argument by value, requiring a copy or move copy constructor.
If you fix 1. to take a const reference, gcc gives the following error:
error: 'Foo& Foo::operator=(const Foo&) [with Ty = int]' is private
If you fix 2. so that the template assignment operator takes a const reference, the code compiles without errors.
Your assignment operator passes argument by value, so it uses copy ctor:
template<typename U>
Foo& operator=(Foo<U> rv)
Possible solution to pass it by const refernce:
template<typename U>
Foo& operator=(const Foo<U> &rv)
A private version
private:
Foo(Foo&);
Foo& operator=(Foo&);
cannot be called because it takes non-const lvalue reference so
Foo& operator=(Foo<U> rv)
this version is called but it takes parameter by value and copy constructor has to be invoked.
I am stuck at a single error. Here is my code:
template<class t>
class smart_ptr{
t *ptr;
public:
smart_ptr(t *p):ptr(p){cout<<"smart pointer copy constructor is called"<<endl;}
~smart_ptr(){cout<<"smart pointer destructor is called"<<endl;delete(ptr);}
t& operator *(){cout<<"returning the * of pointer"<<endl;return(*ptr);}
t* operator ->(){cout<<"returning the -> of pointer"<<endl;return(ptr);}
t* operator=(const t &lhs){ptr=lhs;cout<<"assignement operator called"<<endl;}
};
class xxx{
int x;
public:
xxx(int y=0):x(y){cout<<"xxx constructor called"<<endl;}
~xxx(){cout<<"xxx destructor is called"<<endl;}
void show(){cout<<"the value of x="<<x<<endl;}
};
int main(int argc, char *argv[])
{
xxx *x1=new xxx(50);
smart_ptr<xxx *> p1(x1);
return 0;
}
While compilation I am getting below error
smart_pointer_impl.cpp: In function ‘int main(int, char**)’:
smart_pointer_impl.cpp:27: error: no matching function for call to ‘smart_ptr::smart_ptr(xxx*&)’
smart_pointer_impl.cpp:7: note: candidates are: smart_ptr::smart_ptr(t*) [with t = xxx*]
smart_pointer_impl.cpp:4: note: smart_ptr::smart_ptr(const smart_ptr&)
Any help for a solution is most welcome.
Presumably smart_ptr is template<class t> and then in the main there was intended to be smart_ptr<xxx> instead of smart_ptr<xxx*>?
You need to change ::
smart_ptr<xxx *> p1(x1); to smart_ptr<xxx> p1(x1);
it will work.
You have, I hope, forgotten the first line of your code, that being
template<class t>
and this line:
smart_ptr<xxx *> p1(x1);
should be:
smart_ptr<xxx> p1(x1);
You've not declared your class smart_ptr as a template
template <TYPE>
class smart_ptr{
TYPE *ptr;
public:
smart_ptr(TYPE *p):ptr(p){cout<<"smart pointer copy constructor is called"<<endl;}
~smart_ptr(){cout<<"smart pointer destructor is called"<<endl;delete(ptr);}
TYPE& operator *(){cout<<"returning the * of pointer"<<endl;return(*ptr);}
TYPE* operator ->(){cout<<"returning the -> of pointer"<<endl;return(ptr);}
TYPE* operator=(const TYPE &lhs){ptr=lhs;cout<<"assignement operator called"<<endl;}
};
Also, you're declaring your pointer as of type 'pointer to xxx' but your template class is of a pointer to the type. Try:
smart_ptr<xxx> p1(x1);