The following code creates a temporary object A and pushes it into a vector. The copy constructor is deleted and the move constructor is called during the push_back. I am not sure the design of this code is correct, and surely there is a memory leak.
#include<iostream>
#include<vector>
using namespace std;
class A
{
private:
char* ptr;
public:
A(const string& str)
{
ptr = new char[str.size()];
copy(str.begin(), str.end(), ptr);
cout << ptr << " Constructor\n" ;
}
A(const A& a) = delete; // copy constructor
A( A&& a)
{
cout << "Move constructor\n";
ptr = a.ptr;
a.ptr = nullptr;
}
~A()
{
cout << ptr << " Destructor\n";
delete[] ptr;
ptr = nullptr;
}
void print()
{
cout << ptr << endl;
}
};
int main()
{
vector<A> v;
v.reserve(5);
v.push_back( A("hello") );
v[0].print();
cout << "here" << endl;
return 0;
}
The output is:
hello Constructor
Move constructor
Why the print function doesn't print, and the destructor is not called? Thanks
Since C++11, push_back will perform a move instead of a copy if the argument is an rvalue reference.
It does not make deep copies, since cv::Mat 's are shared pointers. You have to use clone() or similar when adding to the vector images .
As pointed out in a comment, your problem lies here:
~A()
{
cout << ptr << " Destructor\n";
delete[] ptr;
ptr = nullptr;
}
By the time you reach the destructor the object has already been moved from and ptr == nullptr
. The char*
overload of <<
expects a null-terminated string. If ptr
does not point to a null-terminated string you invoke undefined behavior.
You get the expected output if you change it to
cout << static_cast<void*>(ptr) << " Destructor\n";
Because the overload for void*
just prints the value of the pointer.
Working Demo
Your code has undefined behavior on account of you essentially doing
std::cout << (char*)nullptr;
Recall that your moved-from object has its pointer set to nullptr
.
That's a precondition violation of those standard library inserters:
[ostream.inserters.character]
template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& out, const charT* s); template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& out, const char* s); template<class traits> basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>& out, const char* s); template<class traits> basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>& out, const signed char* s); template<class traits> basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>& out, const unsigned char* s);
3 Preconditions:
s
is not a null pointer.
Add a null check, or just don't print the pointer value in the destructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With