【c++】拷贝控制具体分析
我们可以定义拷贝操作,使类的行为看起来像一个值或者像一个指针,这取决于如何拷贝指针成员。
当我们拷贝一个像值的对象时,副本和原对象是完全独立的,改变副本不会对原对象有任何影响,反之亦然。标准库容器和string类的行为像一个值。
当我们拷贝一个行为像指针的类的对象时,副本和原对象使用相同的底层数据,改变副本也会改变原对象,反之亦然。
浅拷贝,指的是在对象复制时,只是对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。这样一来可能出现多个指针指向同一块内存的情况
在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间
一、行为像值的类(不同的类对象的指针数据成员指向独立的内存空间)
class HasPtr
{
public:
HasPtr(const HasPtr&) :ps(new string(*p.ps), i(p.i)){}
HasPtr& operator=(const HasPtr &);
~HasPtr(){ delete ps; }
private:
string *ps;
int i;
};
/*
通过先拷贝右侧运算对象,我们可以处理自赋值情况,并能保证异常发生时代码安全。
注意:1、返回值 2、自赋值 3、new异常。 解决方案:返回引用,先判断是否自赋值,若是则返回,在释放旧内存前先分配好内存
*/
HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
auto newp = new string(*rhs.ps);//拷贝底层string
delete ps;//释放旧内存
ps = newp;
i = rhs.i;
//处理连锁赋值
return *this;
} HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
delete ps;//释放旧内存
//如果rhs和*this是同一个对象,我们就将从已释放的内存中拷贝数据
ps = new string(*rhs.ps);
i = rhs.i;
return *this;
}
二、定义行为像指针的类(多个类对象的指针指向同一个地址,但不能出现错误)
因为可能会有多个类的指针指向同一个地址,所以使用引用计数,引用计数是个指针,如果是个值得话,考虑下面情况(值得话每个对象都保存一个副本,互相独立)。
HasPtr p1("ljy");
HasPtr p2(p1);
HasPtr p3(p1);//p1,p2,p3指向相同的string,若引用计数是值的话,无法更新
class HasPtr
{
private:
string *ps;
int i;
int *use;
public:
HasPtr(const HasPtr &p) :ps(p.ps), i(p.i), use(p.use){ ++*use; }
HasPtr& operator=(const HasPtr&);
~HasPtr();
}; HasPtr::~HasPtr()
{
if (--*use == )
{
delete ps;
delete use;
}
} HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
//先++rhs.use,可以处理自赋值的情况
++*rhs.use;
if (--*use == )
{
delete ps;
delete use;
}
ps = rhs.ps;
i = rhs.i;
use = rhs.use;
return *this;
}
【c++】拷贝控制具体分析的更多相关文章
- C++ Primer : 第十三章 : 拷贝控制之对象移动
右值引用 所谓的右值引用就是必须将引用绑定到右值的引用,我们通过&&来绑定到右值而不是&, 右值引用只能绑定到即将销毁的对象.右值引用也是引用,因此右值引用也只不过是对象的别名 ...
- C++ Primer : 第十三章 : 拷贝控制之拷贝控制和资源管理
定义行为像值的类 行为像值的类,例如标准库容器和std::string这样的类一样,类似这样的类我们可以简单的实现一个这样的类HasPtr. 在实现之前,我们需要: 定义一个拷贝构造函数,完成stri ...
- C++的那些事:类的拷贝控制
1,什么是类的拷贝控制 当我们定义一个类的时候,为了让我们定义的类类型像内置类型(char,int,double等)一样好用,我们通常需要考下面几件事: Q1:用这个类的对象去初始化另一个同类型的对象 ...
- C++ Primer : 第十三章 : 拷贝控制之拷贝、赋值与销毁
拷贝构造函数 一个构造函数的第一个参数是自身类类型的引用,额外的参数(如果有)都有默认值,那么这个构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是一个引用类型. 合成的拷贝构造函数 在我们没 ...
- Chapter13:拷贝控制
拷贝控制操作:拷贝构造函数.拷贝赋值运算符.移动构造函数.移动赋值运算符.析构函数. 实现拷贝控制操作的最困难的地方是首先认识到什么时候需要定义这些操作. 拷贝构造函数: 如果一个构造函数的第一个参数 ...
- C++ 拷贝控制和资源管理,智能指针的简单实现
C++ 关于拷贝控制和资源管理部分的笔记,并且介绍了部分C++ 智能指针的概念,然后实现了一个基于引用计数的智能指针.关于C++智能指针部分,后面会有专门的研究. 通常,管理类外资源的类必须定义拷贝控 ...
- c/c++ 拷贝控制 构造函数的问题
拷贝控制 构造函数的问题 问题1:下面①处的代码注释掉后,就编译不过,为什么??? 问题2:但是把②处的也注释掉后,编译就过了,为什么??? 编译错误: 001.cpp: In copy constr ...
- c/c++ 拷贝控制 右值与const引用
拷贝控制 右值与const引用 背景:当一个函数的返回值是自定义类型时,调用侧用什么类型接收?? 1,如果自定义类型的拷贝构造函数的参数用const修饰了:可以用下面的方式接收. Test t2 = ...
- C++ Primer 笔记——拷贝控制
1.如果构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数.拷贝构造函数的第一个参数必须是引用类型(否则会无限循环的调用拷贝构造函数). 2.如果没有为一个类 ...
随机推荐
- iview分析
- C-基础:函数返回局部变量
一般的来说,函数是可以返回局部变量的. 局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放了.因此,如果函数返回的是局部变量的值,不涉及地址,程序不会出错.但是如果返回的是局部变量的地 ...
- 尺取法 || emmmm
给定两个上升的数组,一个数组任取一个数,求两个数差的min 尺取法emm 也不知道对不对 #include <stdio.h> #include <stdlib.h> #def ...
- 使用Spring IoC进行Bean装配
Spring概述 Spring的设计严格遵从的OCP(开闭原则),保证对修改的关闭,也就是外部无法改变spring内部的运行流程:提供灵活的扩展接口,也就是可以通过extends,implements ...
- 【HIHOCODER 1478】 水陆距离(BFS)
描述 给定一个N x M的01矩阵,其中1表示陆地,0表示水域.对于每一个位置,求出它距离最近的水域的距离是多少. 矩阵中每个位置与它上下左右相邻的格子距离为1. 输入 第一行包含两个整数,N和M. ...
- luoguT21777
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> ...
- Using TCP keepalive under Linux
Linux has built-in support for keepalive. You need to enable TCP/IP networking in order to use it. Y ...
- xtu summer individual 1 C - Design the city
C - Design the city Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu D ...
- SQL中varchar和nvarchar的基本介绍及其区别
SQL中varchar和nvarchar的基本介绍及其区别 varchar(n) 长度为 n 个字节的可变长度且非 Unicode 的字符数据.n 必须是一个介于 1 和 8,000 之间的数值.存储 ...
- (3)梯度下降法Gradient Descent
梯度下降法 不是一个机器学习算法 是一种基于搜索的最优化方法 作用:最小化一个损失函数 梯度上升法:最大化一个效用函数 举个栗子 直线方程:导数代表斜率 曲线方程:导数代表切线斜率 导数可以代表方向, ...