明明白白c++ effective c++ 条目11-15 (一)

2014-11-24 02:32:58 · 作者: · 浏览: 4

条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符
这个条款的原因在哪里呢?
就是如果你创建一个类,什么都不做,那么类会给你创建一个默认构造函数,默认析构函数,默认拷贝函数和默认赋值函数。


所以出问题就出在默认上面去了,尤其是默认拷贝函数和默认赋值函数出的问题最多。
默认拷贝函数会怎么做呢,对于a=b,它会将b中的成员逐位拷贝给另一个a,如果通过指针动态分配内存,则仅仅将指针的值赋给a。
这会导致至少两个问题:
第一,b曾指向的内存永远不会被删除,因而会永远丢失。这是产生内存泄漏的典型例子。第二,现在a和b包含的指针指向同一个字符串,那么只要其中一个离开了它的生存空间,其析构函数就会删除掉另一个指针还指向的那块内存。

看下面代码:


[cpp]
#include
#include
#include
using namespace std;

class MyString
{
public:
MyString(const char* value);
~MyString();
friend ostream& operator << (ostream& os,MyString &c);
private:
char *data;

};

MyString::MyString(const char* value)
{
if(value){
data = new char[strlen(value)+1];
strcpy(data,value);
}
else{
data = new char[1];
data = '\0';
}
}

ostream& operator << (ostream& os,MyString &c)
{
os< return os;
}
MyString::~MyString()
{
delete []data;
}

int main()
{
MyString a("hello");
{
MyString b("world");
b = a;
}
MyString c = a;

cout<
}

#include
#include
#include
using namespace std;

class MyString
{
public:
MyString(const char* value);
~MyString();
friend ostream& operator << (ostream& os,MyString &c);
private:
char *data;

};

MyString::MyString(const char* value)
{
if(value){
data = new char[strlen(value)+1];
strcpy(data,value);
}
else{
data = new char[1];
data = '\0';
}
}

ostream& operator << (ostream& os,MyString &c)
{
os< return os;
}
MyString::~MyString()
{
delete []data;
}

int main()
{
MyString a("hello");
{
MyString b("world");
b = a;
}
MyString c = a;

cout<

}

看到输出的结果是这样的
#a #a
Aborted (core dumped)
可以看到c得不到正确的值,同时析构函数调用的时候出现崩溃的问题。


所以,如果你会调用拷贝构造函数和赋值函数,那么一定要显示的声明他们,否则将他们定义为私有的。


那么下面就看看如何显示的声明他们,如下
[cpp]
MyString::MyString()
{
data = NULL;
}

MyString::MyString(MyString &myString)
{
if (this == &myString)
{
return;
}
else
{
if(myString.data != NULL)
{
data = new char[strlen(myString.data)];
strcpy(data,myString.data);
}
else
{
data = new char[1];
data = '\0';
}
}

}

MyString & MyString::operator= (const MyString &myString)
{
if (this == &myString)
{
return *this;
}
else
{
delete []data;
if(myString.data != NULL)
{
data = new char[strlen(myString.data)];
strcpy(data,myString.data);
}
else
{
data = new char[1];
data = '\0';
}
}
return *this;
}

MyString::MyString()
{
data = NULL;
}

MyString::MyString(MyString &myString)
{
if (this == &myString)
{
return;
}
else
{
if(myString.data != NULL)
{
data = new char[strlen(myString.data)];
strcpy(data,myString.data);
}
else
{
data = new char[1];
data = '\0';
}
}

}

MyString & MyString::operator= (const MyString &myString)
{
if (this == &myString)
{
return *this;
}
else
{
delete []data;
if(myString.data != NULL)
{
data = new char[strlen(myString.data)];
strcpy(data,myString.data);
}
else
{
data = new char[1];
data = '\0';
}
}
return *this;
}

这里需要注意几点:
1 MyString c = a; 实际上调用的是MyString::MyString(MyString &myString), 而不是重载 =号的函数。
你可以用vs或者gdb来单步调试。原