C++类声明中,编译器会默认帮助程序员生成一些他们未定义的成员函数,这样的函数被称为“默认函数”,这包括了以下一些自定义类型的成员函数:
1.构造函数;
2.拷贝构造函数
3.拷贝赋值函数(operator= (const Class & T) )
4.移动构造函数
5.移动拷贝赋值函数(operator= (Class&& T) )
6.析构函数
但是程序员一旦在类的定义中显式地声明上述构造函数的任何一种,则编译器将不会在为该类定义该种类下的默认版本。最常见的便是一旦声明了带参构造函数,则同时也需要程序员自己提供无参构造函数,否则该类将不存在无参构造函数。(但不是说定义了构造函数,系统不提供拷贝构造函数、移动构造函数等,即上述1、2、 3等之间彼此不冲突)。
#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <string.h>
using namespace std;
class CMyString {
private:
char * buf;
int len;
private:
void copy(const char* s) {
buf = new char[len+1];
memcpy(buf, s, len);
buf[len] = '\0';
}
public:
CMyString() {
std::cout << "non-param constructor" << std::endl;
buf = nullptr;
len = 0;
}
CMyString(const char* str = nullptr) {
if (str == nullptr) {
std::cout << "one-param constructor" << std::endl;
buf = nullptr;
len = 0;
}
else {
std::cout << "one-param constructor: " << str << std::endl;
len = strlen(str);
copy(str);
}
}
CMyString(const CMyString& str) { //拷贝构造函数
std::cout << "copy constructor: " << str.buf << std::endl;
len = str.len;
copy(str.buf);
}
CMyString(CMyString&& str) {
std::cout << "move constructor: " << str.buf << std::endl; //移动构造函数
//也可以直接使用std::move
len = str.len;
buf = str.buf;
str.len = 0;
str.buf = nullptr;
}
CMyString& operator=(const CMyString& str) {
std::cout << "copy and assignment func: " << str.buf << std::endl; //拷贝赋值函数
if (&str != this) {
if (buf != nullptr) {
delete[] buf;
buf = nullptr;
}
len = str.len;
copy(str.buf);
}
return *this;
}
CMyString& operator=(CMyString&& str) {
std::cout << "move and assignment func: " << str.buf << std::endl; //移动赋值函数
if (this != &str) {
if (buf != nullptr) {
delete[] buf;
buf = nullptr;
}
len = str.len;
buf = str.buf;
str.len = 0;
str.buf = nullptr;
}
return *this;
}
~CMyString() {
if (buf == nullptr)
{
std::cout << "destructor" << std::endl;
}
else
{
std::cout << "destructor: " << buf << std::endl;
delete[] buf;
buf = nullptr;
}
}
void print() {
if (buf != nullptr)
std::cout << buf << std::endl;
else
std::cout << "buf is null" << std::endl;
}
};
void func1(CMyString str) {
}
CMyString func2() {
CMyString s("34");
std::cout << "Resource from " << __func__ << ": " << hex << &s << endl;
return s;
}
void func3(CMyString && str) {
CMyString tmp = std::move(str); //move constructor
//CMyString tmp = str; //copy constructor这是因为虽然str初始声明为右值引用,但一旦
//占据表达式右值的位置时,则该右值引用的语义将变成不折不扣的左值,除非用move强制声明
}
void test0() {
CMyString s1("12");
func1(s1); //对象str尚未初始化,会调用拷贝构造函数
CMyString s2(func2()); // 对象s2尚未初始化,会产生临时对象,调用移动构造函数
std::cout << "Resource from " << __func__ << ": " << std::hex << &s2 << endl;
//这一步存在一步编译器优化,比移动语义更加激进的优化方式,直接将func2()返回的temp对象
//的指针,直接赋给s2,故这一步实际并没有调用任何构造函数RVO return value optimization
//CMyString s2(std::move(func2())); //这样写则会体现出移动语义的鸠占鹊巢,存在临时对象的构造和析构
CMyString s3 = "56";//对象s3尚未初始化,虽然是有'=6',但是其实依旧调用带参构造函数
s3 = s1; //对象s3已初始化,会调用拷贝赋值函数
func3(static_cast<CMyString&&> (s1) );
s1.print();
cout << "now comes to the destructor part:" << endl;
}
void test1() {
CMyString s4 = "78";
std::vector<CMyString> v1;
//v1.push_back(s4);
v1.push_back(std::move(s4)); // 对象尚未初始化,会调用移动构造函数
std::cout << "v1 vector-container list:\n";
for (auto& str : v1)
str.print();
std::vector<CMyString> v2;
v2 = std::move(v1);
std::cout << "v1 content:\n";
for (auto& str : v1)
str.print();
std::cout << "v2 content:\n";
for (auto& str : v2)
str.print();
}
void test2() {
CMyString s5 = "9";
s5 = func2(); // 对象s5已初始化, 会产生临时对象,调用移动赋值函数
}
int main(void)
{
std::cout << "begin test0()" << std::endl;
test0();
std::cout << std::endl;
std::cout << "begin test1()" << std::endl;
test1();
std::cout << std::endl;
std::cout << "begin test2()" << std::endl;
test2();
return 0;
}