C++赋值和复制
C++赋值和复制
目录
一.说明
c++11 值的类型分为 左值, 纯右值,将亡值(return 返回). 将亡值属于右值. c++11 中引入了右值引用和移动语义,可以避免无谓的复制,提高了程序的性能,右值引用标记为T&&.(右值被使用的对象不再拥有变量的控制权(指针成员,不能再使用,已经移到到赋值对象),加快大对象的复制)
在模板中右值的特性:
-
左值和右值是独立于它们的类型,右值引用类型可能是左值也可能是右值
-
auto&&或函数参数类型的自动推导的T&&是一个未定的引用类型, 它可能是左值引用,也可能是右值引用,取决于初始化的值类型
-
所有的右值引用叠加到右值引用上仍然是一个右值引用,其它引用叠加都为左值引用, (&& + && 输出 右值 , 其它情况 输出左值),当T&&为模版参数时,输入左值,它会变为左值引用, 输入右值则变为具名的右值引用 (模板的&&参数为虚化的右值,由实际输入决定)
-
编译器会将已命名的右值引用视为左值,而将未命名的右值视为右值
在非模板中
如果需要在非复制构造与赋值函数的参数为右值输入类型,需要显示声明(可以和左值参数 重载)
std::move
:将左值变为右值, 前提参数没有const修饰(传入const修饰的变量依然为左值)std::forward
:完美转发模板输入类型(左值输入,输出左值 右值输入,输出右值)
二.例程
各种构造函数,右值使用,如下:
class mmt
{
public:
template<typename T> //模板中: 带有&&的参数,是否为右值由输入参数类型最终决定!
static void formatArgEnd(std::vector<WStfmt> &tab, T&& a) //a右值输入, 可接收左值和右值,
{
//tab.emplace_back(a); 调用左值算法
tab.emplace_back(std::forward<T>(a)); //调用 左值或者右值算法,后面不能访问a (具体类型由a 输入决定)
//emplace_back 支持左值或者右值类型 (如果a有右值构造函数执行右值构造,否则执行左值构造函数)
}
template<typename ...ARG>
static WString formats(const char *pfmt, ARG&&... args) //模板 && args 可接收左值与右值 (非模板函数&&只能接收右值)
{
constexpr u32 argNum = sizeof ... (args); //可变参数的个数
std::vector<WStfmt> tab;
tab.reserve(argNum); //保留 argNum个数的空间
(void)std::initializer_list<int> {(formatArgEnd(tab, std::forward<ARG>(args)), 0)...}; //std::forward 转发输入的args具体的类型(后面不能再访问args)
//std::initializer_list 将可变参数展开(编译阶段已经展开)
//如 formats("123", 1, 2, 3) 展开类型如下:(依次执行下列语句)
// formatArgEnd(tab, 1)
// formatArgEnd(tab, 2)
// formatArgEnd(tab, 3)
return WString::formatStfmt(pfmt, tab.data(), (s32)tab.size());
}
};
class CPoint
{
public:
~CPoint() //析构函数
{
WDBG("析构");
if(m_p != WNULL)
{
WDBG("释放内存");
delete []m_p;
}
}
CPoint() : m_x(0), m_y(0)
{
m_p = new char[100];
WDBG("构造");
}
CPoint(s32 xIn) : m_x(xIn), m_y(0)
{
m_p = new char[100];
WDBG("有参构造1");
}
CPoint(s32 xIn, s32 yIn) : m_x(xIn), m_y(yIn)
{
m_p = new char[100];
WDBG("有参构造");
}
CPoint(const CPoint &p) : m_x(p.m_x), m_y(p.m_y) //左值复制构造
{
m_p = new char[100];
memcpy(m_p, p.m_p, 100);
WDBG("复制构造");
}
CPoint(CPoint &&p) : m_x(p.m_x), m_y(p.m_y) //右值复制构造 c++11才有 (如果内部有指针直接等号)
{
m_p = p.m_p; //不用复制内容,只修改指针指向
p.m_p = WNULL;
WDBG("复制构造 右值");
}
CPoint& operator=(const CPoint &p) //左值赋值
{
WDBG("赋值");
m_x = p.m_x;
m_y = p.m_y;
memcpy(m_p, p.m_p, 100);
return *this;
}
CPoint& operator=(CPoint &&p) //右值赋值 c++11才有
{
WDBG("赋值 右值");
m_x = p.m_x;
m_y = p.m_y;
delete []m_p; //不用复制内容,只修改指针指向
m_p = p.m_p;
p.m_p = WNULL;
return *this;
}
CPoint& operator+=(const CPoint &p) //其它和自己相加
{
WDBG("operator +=");
m_x += p.m_x;
m_y += p.m_y;
return *this;
}
//判断相等
friend bool operator==(const CPoint &p1, const CPoint &p2)
{
WDBG("operator ==");
return ((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y));
}
//判断不相等
friend bool operator!=(const CPoint &p1, const CPoint &p2)
{
WDBG("operator !=");
return !(p1 == p2);
}
//2个任意操作数相加
friend CPoint operator+(const CPoint &p1, const CPoint &p2)
{
WDBG("operator+");
return CPoint(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
std::string toString() const;
s32 m_x;
s32 m_y;
char *m_p;
};
std::string CPoint::toString() const
{
return WString::formats("[%, %]", m_x, m_y);
}
struct Pset
{
public:
Pset()
{
}
~Pset()
{
}
void set(const CPoint &pt)
{
CPoint pm(pt);
WDBG("set 左值");
}
void set(CPoint &&pt)
{
CPoint pm(pt); //参数进入函数后变为左值,如果需要为右值需显示移动
WDBG("set 右值,pm左值");
}
void set2(CPoint &&pt)
{
CPoint pm(std::move(pt));
WDBG("set 右值,pm右值");
}
};
static void func2(CPoint &&p)
{
WDBG("func in p1");
CPoint p1(p); //调用左值
WDBG("\r\n");
WDBG("func in p2");
CPoint p2(std::move(p));
WDBG("\r\n");
WDBG("func out");
}
static void test()
{
WDBG("\r\n");
{
WDBG("\r\n");
WDBG("p1");
CPoint p1;
WDBG("\r\n");
WDBG("p2");
CPoint p2(p1);
WDBG("\r\n");
WDBG("p3");
CPoint p3;
WDBG("\r\n");
WDBG("p3=p2");
p3 = p2;
WDBG("\r\n");
WDBG("p5(std::move(p3))");
CPoint p5(std::move(p3)); //强制将p3 变为右值
//后面 不允许访问p3
WDBG("\r\n");
WDBG("p6");
CPoint p6;
WDBG("\r\n");
WDBG("p6 = std::move(p5)");
p6 = std::move(p5);
//后面 不允许访问p5
}
{
WDBG("\r\n");
WDBG("p10");
CPoint p10;
func2(std::move(p10));
}
{
WDBG("\r\n");
WDBG("30");
CPoint p1;
CPoint p2(1, 2);
CPoint p3;
WDBG("\r\n");
WDBG("p1==p2");
if(p1 == p2)
{
WDBG("P1 == P2");
}
else
{
WDBG("P1 != P2");
}
WDBG("\r\n");
WDBG("p3 = p1 + p2");
p3 = p1 + p2;
WDBG("\r\n");
WDBG("p3 = p1 + 1");
p3 = p1 + 1; //重要 如果参数能用指定的构造方法实现.既能实现调用!!!!
WDBG("\r\n");
WDBG("p3 = 2");
p3 = 2; //重要 如果参数能用指定的构造方法实现.既能实现调用!!!!
}
{
WDBG("\r\n");
WDBG("pa[3]");
CPoint pa[3] = {CPoint(), CPoint(1, 2), CPoint(2, 3)}; //重要类数组初始化!!
for(auto const &v : pa)
{
WDBG("res[%]", v);
}
}
WDBG("\r\n");
{
WDBG("\r\n");
WDBG("Pset");
CPoint p(1, 2);
CPoint p2(1, 2);
Pset st;
WDBG("\r\n");
WDBG("Pset 左值");
st.set(p);
WDBG("\r\n");
WDBG("Pset 右值, 内左");
st.set(std::move(p));
WDBG("\r\n");
WDBG("Pset 右值,内右");
st.set2(std::move(p2));
//st.set2(p2); 编译不过,没有提供左值算法
}
}
/*
[DBG] [2021-06-17 12:21:13.224] [main.cpp::test:249] p1
[DBG] [2021-06-17 12:21:13.224] [main.cpp::CPoint:86] 构造
[DBG] [2021-06-17 12:21:13.224] [main.cpp::test:252]
[DBG] [2021-06-17 12:21:13.225] [main.cpp::test:253] p2
[DBG] [2021-06-17 12:21:13.225] [main.cpp::CPoint:106] 复制构造
[DBG] [2021-06-17 12:21:13.225] [main.cpp::test:256]
[DBG] [2021-06-17 12:21:13.225] [main.cpp::test:257] p3
[DBG] [2021-06-17 12:21:13.225] [main.cpp::CPoint:86] 构造
[DBG] [2021-06-17 12:21:13.225] [main.cpp::test:260]
[DBG] [2021-06-17 12:21:13.225] [main.cpp::test:261] p3=p2
[DBG] [2021-06-17 12:21:13.226] [main.cpp::operator=:118] 赋值
[DBG] [2021-06-17 12:21:13.226] [main.cpp::test:264]
[DBG] [2021-06-17 12:21:13.226] [main.cpp::test:265] p5(std::move(p3))
[DBG] [2021-06-17 12:21:13.226] [main.cpp::CPoint:113] 复制构造 右值
[DBG] [2021-06-17 12:21:13.226] [main.cpp::test:269]
[DBG] [2021-06-17 12:21:13.226] [main.cpp::test:270] p6
[DBG] [2021-06-17 12:21:13.227] [main.cpp::CPoint:86] 构造
[DBG] [2021-06-17 12:21:13.227] [main.cpp::test:273]
[DBG] [2021-06-17 12:21:13.227] [main.cpp::test:274] p6 = std::move(p5)
[DBG] [2021-06-17 12:21:13.227] [main.cpp::operator=:128] 赋值 右值
[DBG] [2021-06-17 12:21:13.227] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.227] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.227] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.227] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.227] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.227] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.228] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.228] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.228] [main.cpp::test:280]
[DBG] [2021-06-17 12:21:13.228] [main.cpp::test:281] p10
[DBG] [2021-06-17 12:21:13.228] [main.cpp::CPoint:86] 构造
[DBG] [2021-06-17 12:21:13.228] [main.cpp::func2:226] func in p1
[DBG] [2021-06-17 12:21:13.228] [main.cpp::CPoint:106] 复制构造
[DBG] [2021-06-17 12:21:13.228] [main.cpp::func2:230]
[DBG] [2021-06-17 12:21:13.228] [main.cpp::func2:231] func in p2
[DBG] [2021-06-17 12:21:13.228] [main.cpp::CPoint:113] 复制构造 右值
[DBG] [2021-06-17 12:21:13.228] [main.cpp::func2:235]
[DBG] [2021-06-17 12:21:13.228] [main.cpp::func2:236] func out
[DBG] [2021-06-17 12:21:13.228] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.228] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.228] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:288]
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:289] 30
[DBG] [2021-06-17 12:21:13.229] [main.cpp::CPoint:86] 构造
[DBG] [2021-06-17 12:21:13.229] [main.cpp::CPoint:98] 有参构造
[DBG] [2021-06-17 12:21:13.229] [main.cpp::CPoint:86] 构造
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:295]
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:296] p1==p2
[DBG] [2021-06-17 12:21:13.229] [main.cpp::operator==:149] operator ==
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:303] P1 != P2
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:306]
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:307] p3 = p1 + p2
[DBG] [2021-06-17 12:21:13.229] [main.cpp::operator+:163] operator+
[DBG] [2021-06-17 12:21:13.229] [main.cpp::CPoint:98] 有参构造
[DBG] [2021-06-17 12:21:13.229] [main.cpp::operator=:128] 赋值 右值
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:310]
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:311] p3 = p1 + 1
[DBG] [2021-06-17 12:21:13.229] [main.cpp::CPoint:92] 有参构造1
[DBG] [2021-06-17 12:21:13.229] [main.cpp::operator+:163] operator+
[DBG] [2021-06-17 12:21:13.229] [main.cpp::CPoint:98] 有参构造
[DBG] [2021-06-17 12:21:13.229] [main.cpp::operator=:128] 赋值 右值
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:314]
[DBG] [2021-06-17 12:21:13.229] [main.cpp::test:315] p3 = 2
[DBG] [2021-06-17 12:21:13.229] [main.cpp::CPoint:92] 有参构造1
[DBG] [2021-06-17 12:21:13.229] [main.cpp::operator=:128] 赋值 右值
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.229] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:320]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:321] pa[3]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:86] 构造
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:98] 有参构造
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:98] 有参构造
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:326] res[[0, 0]]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:326] res[[1, 2]]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:326] res[[2, 3]]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:332]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:335]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:336] Pset
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:98] 有参构造
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:98] 有参构造
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:343]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:344] Pset 左值
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:106] 复制构造
[DBG] [2021-06-17 12:21:13.230] [main.cpp::set:196] set 左值
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:347]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:348] Pset 右值, 内左
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:106] 复制构造
[DBG] [2021-06-17 12:21:13.230] [main.cpp::set:203] set 右值,pm左值
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:351]
[DBG] [2021-06-17 12:21:13.230] [main.cpp::test:352] Pset 右值,内右
[DBG] [2021-06-17 12:21:13.230] [main.cpp::CPoint:113] 复制构造 右值
[DBG] [2021-06-17 12:21:13.230] [main.cpp::set2:210] set 右值,pm右值
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:73] 析构
[DBG] [2021-06-17 12:21:13.230] [main.cpp::~CPoint:77] 释放内存
*/