C++类的拷贝构造(Copy constructor)函数隐藏陷阱

好长时间没写C++了,今天写了个很简单的String类,竟然调试了半天,最终发现了一个十分隐蔽的陷阱,写出来供大家分享。

C++中类的拷贝构造函数的作用就是通过类的一个对象来实例化另一个对象。下面是我写的一个MyString类,头文件MyString.h:

#include <iostream>
using namespace std;
class MyString
{
public:
	MyString();
	MyString(const MyString& str);//这里就是我们研究的地方
	MyString(char *p);
	~MyString();
	friend ostream& operator<<(ostream& out,MyString& ms)
	{
		return out<<"m_Data="<<ms.m_Data;
	}

private:
	int m_Length;
	char* m_Data;//注意这里是指针,不是数组
};

再看看第一个类的实现版本:

#include <cstring>
#include "MyString.h"
using namespace std;
MyString::MyString():m_Length(1),m_Data(new char[m_Length])
{
	memcpy(m_Data,"",m_Length);
}

MyString::MyString(const MyString& str)
	:m_Length(str.m_Length),m_Data(new char [m_Length])//这里使用的是new char[],另外说一声,这里的m_Length和m_Data的初始化顺序不能改变,原因自己想就知道了
{
	memcpy(m_Data,str.m_Data,m_Length);
}

MyString::MyString(char *p):m_Length(strlen(p)+1),m_Data(new char[m_Length])
{
	memcpy(m_Data,p,m_Length);
}

MyString::~MyString()
{
	//注意此处;
	delete [] m_Data;
}

使用一个简单的例子来测试(test.cpp):

#include "MyString.h"
#include <iostream>
using namespace std;
int main()
{
	MyString b("backup");
	MyString a(b);
	cout<<a<<endl;
}

结果就是大家熟悉的

再看一下MyString类的第二个实现版本(MyString.cpp)

#include <cstring>
#include "MyString.h"
using namespace std;
MyString::MyString():m_Length(1),m_Data(new char[m_Length])
{
	memcpy(m_Data,"",m_Length);
}

MyString::MyString(const MyString& str)
	:m_Length(str.m_Length),m_Data(str.m_Data)//这里直接复制指针;
{
	//memcpy(m_Data,str.m_Data,m_Length);
}

MyString::MyString(char *p):m_Length(strlen(p)+1),m_Data(new char[m_Length])
{
	memcpy(m_Data,p,m_Length);
}

MyString::~MyString()
{
	//注意此处;
	delete [] m_Data;
}

运行结果就是:

原因其实很简单,设置断点调试一下就知道了。

在第二个版本中,我们直接复制指针,之后的输出没有问题("m_Data=backup"),而根据拷贝构造函数,对象a和b都指向同一个字符数组,执行b的析构函数之后该字符数组的内存空间就没有了,再执行a的析构函数,delete不存在的内存空间就会出现错误了啦。

总结一句:C++还真不愧数一数二难的编程语言,错误都较难发现而且一般都想不到。

时间: 2024-11-05 23:22:22

C++类的拷贝构造(Copy constructor)函数隐藏陷阱的相关文章

为什么类的拷贝构造参数加引用、重载赋值函数的返回值和参数加引用

class string { public: string(const char *str=NULL); string(const string& str);     //copy构造函数的参数为什么是引用呢? string& operator=(const string & str); //赋值函数为什么返回值是引用呢?参数为什么是引用呢? ~string(); }; 下面我就给大家解释一下: class String1 { public: String1(const char*

(C++)关于拷贝构造函数 Copy Constructor

题目: In which of the following scenarios is a Copy Constructor called or invoked? A.    When no conversion function exists for converting the class object to another class object B.    When an existing object is assigned an object of its own class C. 

引用参数与引用返回值 类的拷贝构造

引用地址  http://www.cnblogs.com/bigshow/archive/2008/11/10/1330514.html 经常看到这样的声明:T& func(T& t),这种声明和T func(T t)有什么区别?书上的解释是为了提高效率,究竟是如何提高效率的呢?内部执行了什么操作?本文通过8个小例子对引用参数和引用返回进行了一次彻底的排查.    首先看一下在类的成员函数中的引用参数和引用返回值: 类定义class A{     public:      int x; A

C++构造函数实例——拷贝构造,赋值

#define _CRT_SECURE_NO_WARNINGS //windows系统 #include <iostream> #include <cstdlib> #include <cstring> using namespace std; class student { private: char *name; int age; public: student(const char *n = "no name", int a = 0) { na

15.含有指针成员的类的拷贝(copy constructor)

http://zhedahht.blog.163.com/blog/static/25411174200722710364233/ http://www.cnblogs.com/t427/archive/2012/08/10/2633133.html http://blog.csdn.net/gamecreating/article/details/5382902 http://www.cppblog.com/xczhang/archive/2008/01/21/41569.html 题目:下面

拷贝构造,深度拷贝,关于delete和default相关的操作,explicit,类赋初值,构造函数和析构函数,成员函数和内联函数,关于内存存储,默认参数,静态函数和普通函数,const函数,友元

 1.拷贝构造 //拷贝构造的规则,有两种方式实现初始化. //1.一个是通过在后面:a(x),b(y)的方式实现初始化. //2.第二种初始化的方式是直接在构造方法里面实现初始化. 案例如下: #include<iostream> //如果声明已经定义,边不会生成 class classA { private: int a; int b; public: //拷贝构造的规则,有两种方式实现初始化 //1.一个是通过在后面:a(x),b(y)的方式实现初始化 //2.第二种初始化的方式是直

【C/C++学院】0819-/类的成员函数与const-mutable /构造与析构/拷贝构造deletedefault以及深浅拷贝/静态成员函数成员变量类在内存的存储默认参数/友元类以及友元函数

类的成员函数与const-mutable 成员函数 Fushu.h #pragma once #include <iostream> class fushu { public: int x; int y; public: fushu(); ~fushu(); void show(); inline void showall(int x, int y);//显式内联 void setxy(int x, int y);//编译器优化,默认隐式内联 void show(int x, int y);

类的成员函数(构造、析构、拷贝构造、赋值、运算符重载)的实现

以String类为例实现其成员函数 class String { //友元函数重载运算符 friend ostream& operator<<(ostream &out,String& str); friend istream& operator>>(istream& in, String& str); public: //通用构造函数 String(const char* str) { if(!str) //对m_data加NULL

Copy constructor拷贝构造函数

翻译的是wikipedia关于copy constructor,地址:点击打开链接 拷贝构造函数是C++语言中用一个已有对象创建一个新对象的特殊构造函数,该函数的第一个参数必须是函数所在类型的引用(译注:const/non-const都可以,可以有多个参数剩余参数必须有默认值,一定要是引用,这些原因见后,问:有多个参数拷贝构造如何调用?). 通常编译器会自动为每一个class创建一个拷贝构造函数(显示拷贝构造);有些情况下程序员自定义了拷贝构造函数(用户自定义拷贝构造),这时编译器不合成拷贝构造