MyTime::MyTime(){}
class MyTime
{
public:
MyTime (int n) {...}
};
MyTime mt; // no appropriate constructor
编译报错,没有合适的构造函数
class MyTime
{
public: // two default constructors
MyTime () {...}
MyTime (int n = 0) {...}
};
MyTime mt; // which constructor?
编译报错,不知道调用哪个
MyTime::~MyTime(){}
-Memory allocated in constructors is normally released in a destructor
MyTime::MyTime(MyTime & t){...}
MyTime t1(1, 59);
MyTime t2(t1); // copy constructor
MyTime t3 = t1; // copy constructor
(1) If no user-defined copy constructors, the compiler will generate one
(2) Copy all non-static data members
=, +=, -=
MyTime & MyTime::operator=(MyTime &){...}
MyTime t1(1, 59);
MyTime t2 = t1; // copy constructor
t2 = t1; // copy assignment
(1) If no user-defined copy assignment constructors, the compiler will generate one
(2) Copy all non-static data member
mystring.hpp
#pragma once
#include
#include
class MyString
{
private:
int buf_len;
char * characters;
public:
MyString(int buf_len = 64, const char * data = NULL)
{
std::cout << "Constructor(int, char*)" << std::endl;
this->buf_len = 0;
this->characters = NULL;
create(buf_len, data);
}
~MyString()
{
delete []this->characters;
}
bool create(int buf_len, const char * data)
{
this->buf_len = buf_len;
if( this->buf_len != 0)
{
this->characters = new char[this->buf_len]{};
if(data)
strncpy(this->characters, data, this->buf_len);
}
return true;
}
friend std::ostream & operator<<(std::ostream & os, const MyString & ms)
{
os << "buf_len = " << ms.buf_len;
os << ", characters = " << static_cast<void*>(ms.characters);
os << " [" << ms.characters << "]";
return os;
}
};
main.cpp
#include
#include "mystring.hpp"
using namespace std;
// Why memory leak and memory double free?
int main()
{
MyString str1(10, "Shenzhen");
cout << "str1: " << str1 << endl;
MyString str2 = str1;
cout << "str2: " << str2 << endl;
MyString str3;
cout << "str3: " << str3 << endl;
str3 = str1;
cout << "str3: " << str3 << endl;
return 0;
}
Constructor(int, char*)
str1: buf_len = 10, characters = 0x11e605ef0 [Shenzhen]
str2: buf_len = 10, characters = 0x11e605ef0 [Shenzhen]
Constructor(int, char*)
str3: buf_len = 64, characters = 0x11e605e10 []
str3: buf_len = 10, characters = 0x11e605ef0 [Shenzhen]
a.out(64132,0x1dd21d300) malloc: Double free of object 0x11e605ef0
a.out(64132,0x1dd21d300) malloc: *** set a breakpoint in malloc_error_break to debug
zsh: abort ./a.out
报错。
MyString str1(10, "Shenzhen");
MyString str2 = str1;
调用了拷贝构造函数,默认的拷贝
MyString str3;
调用了默认的构造函数,就是我们定义的构造函数
str3 = str1;
Default Copy Assignment
三个对象指向同一个内存
在这里,当作用域结束,首先释放str3
,直接把character指向的内存释放了,导致后面释放str2
时找不到需要释放的内存,故报错
另外,还有一块内存地址已经没人知道,造成内存泄漏
上一个问题是多个对象指向同一块内存,现在的解决办法是每个对象都要保证拥有自己独立的内存
MyString(const MyString & ms)
{
std::cout << "Constructor(MyString&)" << std::endl;
this->buf_len = 0;
this->characters = NULL;
create(ms.buf_len, ms.characters);
}
create()
release the current memory and allocate a new onethis->characters
will not point to ms.characters
MyString & operator=(const MyString &ms)
{
create(ms.buf_len, ms.characters);
return *this;
}
mystring.hpp
#pragma once
#include
#include
class MyString
{
private:
int buf_len;
char * characters;
public:
MyString(int buf_len = 64, const char * data = NULL)
{
std::cout << "Constructor(int, char*)" << std::endl;
this->buf_len = 0;
this->characters = NULL;
create(buf_len, data);
}
MyString(const MyString & ms)
{
std::cout << "Constructor(MyString&)" << std::endl;
this->buf_len = 0;
this->characters = NULL;
create(ms.buf_len, ms.characters);
}
~MyString()
{
release();
}
MyString & operator=(const MyString &ms)
{
std::cout << "Copy Assignment " << std::endl;
create(ms.buf_len, ms.characters);
return *this;
}
bool create(int buf_len, const char * data)
{
release();
this->buf_len = buf_len;
if( this->buf_len != 0)
{
this->characters = new char[this->buf_len]{};
}
if(data)
strncpy(this->characters, data, this->buf_len);
return true;
}
bool release()
{
this->buf_len = 0;
if(this->characters!=NULL)
{
delete []this->characters;
this->characters = NULL;
}
return 0;
}
friend std::ostream & operator<<(std::ostream & os, const MyString & ms)
{
os << "buf_len = " << ms.buf_len;
os << ", characters = " << static_cast<void*>(ms.characters);
os << " [" << ms.characters << "]";
return os;
}
};
main.cpp
#include
#include "mystring.hpp"
using namespace std;
// Why memory leak and memory double free?
int main()
{
MyString str1(10, "Shenzhen");
cout << "str1: " << str1 << endl;
MyString str2 = str1;
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;
MyString str3;
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;
cout << "str3: " << str3 << endl;
str3 = str1;
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;
cout << "str3: " << str3 << endl;
return 0;
}
Constructor(int, char*)
str1: buf_len = 10, characters = 0x131605ef0 [Shenzhen]
Constructor(MyString&)
str1: buf_len = 10, characters = 0x131605ef0 [Shenzhen]
str2: buf_len = 10, characters = 0x131606040 [Shenzhen]
Constructor(int, char*)
str1: buf_len = 10, characters = 0x131605ef0 [Shenzhen]
str2: buf_len = 10, characters = 0x131606040 [Shenzhen]
str3: buf_len = 64, characters = 0x131605e10 []
Copy Assignment
str1: buf_len = 10, characters = 0x131605ef0 [Shenzhen]
str2: buf_len = 10, characters = 0x131606040 [Shenzhen]
str3: buf_len = 10, characters = 0x131605e70 [Shenzhen]
MyString str1(10, "Shenzhen");
MyString str2 = str1;
调用自己定义的拷贝构造函数
MyString str3;
调用自己定义的构造函数
str3 = str1;
调用自己定义的拷贝赋值函数,先将被赋值的对象的内存销毁,再申请新的地址,并将赋值对象的内容赋值过来
BUt…
union
联合体,共享同一块地址unchar* data;
: 数据指针UMatData* u;
: 用来计算这块内存没引用了多少次Mat::u ->refcount
is used to count the times the memory is referencedCV_XADD
: macro for atomic addCV_XADD(&m.u->refcount, 1);
: 宏对refcount
加1,用宏而不直接加1,是考虑到并行计算的数据冲突问题data = m.data;
: 将被赋值对象的指向赋值对象的同一个内存地址。即还是以下这种情况只不过因为有了指针引用次数,内存释放会等到refcount
的值为0时才进行真正的内存释放
cv::Mat
if (u && CV_XADD(&u->refcount, -1) == 1)
: 宏做减1,返回加法操作前的那个值,也就是当减1为0,加法操作前为1的情况,这个对象是对这个数据的唯一的引用,没有其他的对象引用了,所以可以直接可以申请释放内存C++可不可以只管申请不管释放?
可以。
std::shared_ptr
std::shared_ptr<MyTime> mt1(new MyTime(10));
std::shared_ptr<MyTime> mt2 = mt1;
auto mt1 = std::make_shared<MyTime>(1, 70);
mt2 = mt1
: mt1 和 mt2指向同一个对象shared_ptr.cpp
#include
#include
class MyTime
{
int hours;
int minutes;
public:
MyTime(): hours(0), minutes(0)
{
std::cout << "Constructor MyTime()" << std::endl;
}
MyTime(int m): hours(0), minutes(m)
{
std::cout << "Constructor MyTime(int)" << std::endl;
this->hours += this->minutes / 60;
this->minutes %= 60;
}
MyTime(int h, int m): hours(h), minutes(m)
{
std::cout << "Constructor MyTime(int,int)" << std::endl;
this->hours += this->minutes / 60;
this->minutes %= 60;
}
~MyTime()
{
std::cout << "Destructor MyTime(). Bye!" << std::endl;
}
MyTime operator+(int m) const
{
MyTime sum;
sum.minutes = this->minutes + m;
sum.hours = this->hours;
sum.hours += sum.minutes / 60;
sum.minutes %= 60;
return sum;
}
friend std::ostream & operator<<(std::ostream & os, const MyTime & t)
{
std::string str = std::to_string(t.hours) + " hours and "
+ std::to_string(t.minutes) + " minutes.";
os << str;
return os;
}
};
int main()
{
// std::shared_ptr mt0 = new MyTime(0,70); //error
// MyTime * mt1 = std::make_shared(1, 70); //error
// {
// std::shared_ptr mt1(new MyTime(10));
// std::cout << *mt1 << std::endl;
// }
{
std::shared_ptr<MyTime> mt1 = std::make_shared<MyTime>(1, 70);
std::shared_ptr<MyTime> mt2 = mt1;
std::shared_ptr<MyTime> mt3 = mt2;
std::cout << "mt1: " << *mt1 << std::endl;
std::cout << "mt2: " << *mt2 << std::endl;
std::cout << "mt3: " << *mt3 << std::endl;
std::cout << "use_count() = " << mt2.use_count() << std::endl;
{
auto mt4 = mt3;
*mt4 = *mt4 + 50;
std::cout << "use_count() = " << mt3.use_count() << std::endl;
}
std::cout << "mt3: " << *mt3 << std::endl;
std::cout << "use_count() = " << mt3.use_count() << std::endl;
}
return 0;
}
Constructor MyTime(int,int)
mt1: 2 hours and 10 minutes.
mt2: 2 hours and 10 minutes.
mt3: 2 hours and 10 minutes.
use_count() = 3
Constructor MyTime()
Destructor MyTime(). Bye!
use_count() = 4
mt3: 3 hours and 0 minutes.
use_count() = 3
Destructor MyTime(). Bye!
std::shared_ptr mt1 = std::make_shared(1, 70);
: 触发了构造函数,并使用共享指针std::shared_ptr mt2 = mt1;
: 拷贝赋值并没有触发构造函数,说明只有一个对象use_count()
: 记录有多个指针引用对象auto mt4 = mt3;
: 这里只是拷贝,并没有触发构造函数*mt4 = *mt4 + 50;
:加法运算符有一个临时变量创建,所以触发了构造函数,加法结束后作用域结束,临时变量销毁,触发析构函数std::unique_ptr
std::shared_ptr
, a std::unique_ptr
will point to an object, and not allow others to point tostd::unique_ptr
can be moved to another pointerstd::unique_ptr<MyTime> mt1(new MyTime(10));
std::unique_ptr<MyTime> mt2 = std::make_unique<MyTime>(80); // C++17
std::unique_ptr<MyTime> mt3 = std::move(mt1);
unique_ptr.cpp
#include
#include
class MyTime
{
int hours;
int minutes;
public:
MyTime(): hours(0), minutes(0)
{
std::cout << "Constructor MyTime()" << std::endl;
}
MyTime(int m): hours(0), minutes(m)
{
std::cout << "Constructor MyTime(int)" << std::endl;
this->hours += this->minutes / 60;
this->minutes %= 60;
}
MyTime(int h, int m): hours(h), minutes(m)
{
std::cout << "Constructor MyTime(int,int)" << std::endl;
this->hours += this->minutes / 60;
this->minutes %= 60;
}
~MyTime()
{
std::cout << "Destructor MyTime(). Bye!" << std::endl;
}
MyTime operator+(int m) const
{
MyTime sum;
sum.minutes = this->minutes + m;
sum.hours = this->hours;
sum.hours += sum.minutes / 60;
sum.minutes %= 60;
return sum;
}
friend std::ostream & operator<<(std::ostream & os, const MyTime & t)
{
std::string str = std::to_string(t.hours) + " hours and "
+ std::to_string(t.minutes) + " minutes.";
os << str;
return os;
}
};
int main()
{
std::unique_ptr<MyTime> mt1(new MyTime(10));
std::unique_ptr<MyTime> mt2 = std::make_unique<MyTime>(80); //c++17
std::cout << "mt1: " <<*mt1 << std::endl;
std::cout << "mt2: " <<*mt2 << std::endl;
// std::unique_ptr mt3 = mt1; // error
std::unique_ptr<MyTime> mt3 = std::move(mt1);
// std::shared_ptr mt3 = std::move(mt1);//okay
// std::cout << "mt1: " <<*mt1 << std::endl;
std::cout << "mt3: " <<*mt3 << std::endl;
return 0;
}
g++ unique_ptr.cpp --std=c++17
./a.out
Constructor MyTime(int)
Constructor MyTime(int)
mt1: 0 hours and 10 minutes.
mt2: 1 hours and 20 minutes.
mt3: 0 hours and 10 minutes.
Destructor MyTime(). Bye!
Destructor MyTime(). Bye!
template<class T> class shared_ptr;
template<
class T,
class Deleter = std::default_delete<T>
>class unique_ptr;
mt1
and mt2
are two objects of type shared_ptr<>
std::shared_ptr<MyTime> mt1(new MyTime(10));
std::shared_ptr,MyTime> mt2 = mt1;
#include
#include
using namespace std;
class B;
class A
{
public:
shared_ptr<B> pb;
A() { cout << "Constructor A " << endl;}
~A() {cout << "Destructor A " << endl; }
};
class B{
public:
shared_ptr<A> pa;
B() { cout << "Constructor B "<< endl;}
~B() {cout << "Destructor B " << endl;}
};
int main()
{
shared_ptr<A> spa = make_shared<A> ();
shared_ptr<B> spb = make_shared<B> ();
spa->pb = spb;
spb->pa = spa;
return 0;
}
Constructor A
Constructor B
There is no Destructor invoked, no memory released.
#include
#include
using namespace std;
int main()
{
double *p_reg = new double(5);
shared_ptr<double> pd;
pd = p_reg;
pd = shared_ptr<double>(p_reg);
cout<<"*pd="<<*pd<<endl;
shared_ptr<double> pshared = p_reg;
shared_ptr<double> pshared(p_reg);
cout << "*pshred = " << *pshared << endl;
string str(“Hello World!");
shared_ptr<string> pstr(&str);
cout << "*pstr = " << *pstr << endl;
return 0;
}
Modified:
#include
#include
using namespace std;
int main()
{
shared_ptr<double> p_reg(new double(5));
shared_ptr<double> pd;
pd = p_reg;
cout<<"*pd="<<*pd<<endl;
shared_ptr<double> pshared = p_reg;
cout << "*pshred = " << *pshared << endl;
shared_ptr<string> pstr(new string ("Hello World!"));
cout << "*pstr = " << *pstr << endl;
return 0;
}
float
.shared_ptr
for the matrix data.class Matrix{...};
Matrix a(3,4);
Matrix b(3,4);
Matrix c = a + b;
Matrix d = a;
d = b;
matrix.hpp
#pragma once
#include
#include
class Matrix
{
private:
size_t rows;
size_t cols;
public:
std::shared_ptr<float> data;
Matrix(size_t r, size_t c)
{
std::cout << "Constructor Matrix(r, c) " << std::endl;
if ( r * c == 0)
{
rows = 0;
cols = 0;
data = nullptr;
}
else{
rows = r;
cols = c;
std::shared_ptr<float> temp(new float[r * c]);
data = temp;
}
}
Matrix(const Matrix & m): rows(m.rows), cols(m.cols), data(m.data){
std::cout << "Constructor Matrix(M) " << std::endl;
}
~Matrix() {std::cout << "Destructor Matrix " << std::endl; }
friend std::ostream & operator<<(std::ostream & os, const Matrix & m)
{
os << "size (" << m.rows << "x" << m.cols << ")" << std::endl;
os << "[" << std::endl;
for (size_t r = 0; r < m.rows; r++)
{
for(size_t c = 0; c < m.cols; c++)
os << m.data.get()[r * m.cols + c] << ", ";
os << std::endl;
}
os << "]";
return os;
}
Matrix operator+(const Matrix &m)
{
std::cout << "Matrix Add " << std::endl;
if (this->cols != m.cols || this->rows != m.rows)
{
std::cout << "The two matrices dimension must be the same. " << std::endl;
}
Matrix sum(m.rows, m.cols);
size_t ind = 0;
for (size_t r = 0; r < m.rows; r++)
{
for (size_t c = 0; c < m.cols; c++)
{
ind = r * m.cols + c;
sum.data.get()[ind] = this->data.get()[ind] + m.data.get()[ind];
}
}
return sum;
}
void setElement (int a, int b, float x)
{
this->data.get()[a * this->cols + b] = x;
}
float getElement (int a, int b)
{
return this->data.get()[a * this->cols + b];
}
};
matrix.cpp
#include
#include
#include "matrix.hpp"
int main()
{
Matrix m1(3,8);
Matrix m2(4,8);
std::cout << "&m1 = " << &m1 << std::endl;
std::cout << "&m2 = " << &m2 << std::endl;
std::cout << "m1.data = " << m1.data << std::endl;
std::cout << "m2.data = " << m2.data << std::endl;
std::cout << "m1.data.get() = " << m1.data.get() << std::endl;
std::cout << "m2.data.get() = " << m2.data.get() << std::endl;
m2 = m1;
std::cout << "&m1 = " << &m1 << std::endl;
std::cout << "&m2 = " << &m2 << std::endl;
std::cout << "m1.data = " << m1.data << std::endl;
std::cout << "m2.data = " << m2.data << std::endl;
std::cout << "m1.data.get() = " << m1.data.get() << std::endl;
std::cout << "m2.data.get() = " << m2.data.get() << std::endl;
m1.setElement(1, 2, 4.5f);
std::cout << m2.getElement(1,2) << std::endl;
std::cout << m1 << std::endl;
std::cout << m2 << std::endl;
Matrix m3 = m1 + m2;
std::cout << "&m1 = " << &m1 << std::endl;
std::cout << "&m2 = " << &m2 << std::endl;
std::cout << "&m3 = " << &m3 << std::endl;
std::cout << "m1.data = " << m1.data << std::endl;
std::cout << "m2.data = " << m2.data << std::endl;
std::cout << "m3.data = " << m3.data << std::endl;
std::cout << "m1.data.get() = " << m1.data.get() << std::endl;
std::cout << "m2.data.get() = " << m2.data.get() << std::endl;
std::cout << "m3.data.get() = " << m3.data.get() << std::endl;
Matrix m4 = m1;
std::cout << "&m1 = " << &m1 << std::endl;
std::cout << "&m2 = " << &m2 << std::endl;
std::cout << "&m3 = " << &m3 << std::endl;
std::cout << "&m4 = " << &m4 << std::endl;
std::cout << "m1.data = " << m1.data << std::endl;
std::cout << "m2.data = " << m2.data << std::endl;
std::cout << "m3.data = " << m3.data << std::endl;
std::cout << "m4.data = " << m4.data << std::endl;
std::cout << "m1.data.get() = " << m1.data.get() << std::endl;
std::cout << "m2.data.get() = " << m2.data.get() << std::endl;
std::cout << "m3.data.get() = " << m3.data.get() << std::endl;
std::cout << "m4.data.get() = " << m4.data.get() << std::endl;
std::cout << m3 << std::endl;
std::cout << m4 << std::endl;
return 0;
}
result:
Constructor Matrix(r, c)
Constructor Matrix(r, c)
&m1 = 0x16b8e2fb8
&m2 = 0x16b8e2f98
m1.data = 0x14ae05c70
m2.data = 0x14ae05cd0
m1.data.get() = 0x14ae05c70
m2.data.get() = 0x14ae05cd0
&m1 = 0x16b8e2fb8
&m2 = 0x16b8e2f98
m1.data = 0x14ae05c70
m2.data = 0x14ae05c70
m1.data.get() = 0x14ae05c70
m2.data.get() = 0x14ae05c70
4.5
size (3x8)
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4.5, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
]
size (3x8)
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4.5, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
]
Matrix Add
Constructor Matrix(r, c)
&m1 = 0x16b8e2fb8
&m2 = 0x16b8e2f98
&m3 = 0x16b8e2f68
m1.data = 0x14ae05c70
m2.data = 0x14ae05c70
m3.data = 0x14ae05d20
m1.data.get() = 0x14ae05c70
m2.data.get() = 0x14ae05c70
m3.data.get() = 0x14ae05d20
Constructor Matrix(M)
&m1 = 0x16b8e2fb8
&m2 = 0x16b8e2f98
&m3 = 0x16b8e2f68
&m4 = 0x16b76ef48
m1.data = 0x14ae05c70
m2.data = 0x14ae05c70
m3.data = 0x14ae05d20
m4.data = 0x14ae05c70
m1.data.get() = 0x14ae05c70
m2.data.get() = 0x14ae05c70
m3.data.get() = 0x14ae05d20
m4.data.get() = 0x14ae05c70
size (3x8)
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
]
size (3x8)
[
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 4.5, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
]
Destructor Matrix
Destructor Matrix
Destructor Matrix
Destructor Matrix