C++ 深拷贝构造函数
c++ deep copy constructor
这是我的代码:
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
String& operator=(String &c){
size = strlen(c.s);
s = new char[size+1];
strcpy(s, c.s);
}
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
void String::change(const char *str)
{
delete [] s;
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
int main()
{
String str1("learnc++");
String str2 = str1;
str1.print(); // what is printed ?
str2.print();
str2.change("learnjava");
str1.print(); // what is printed now ?
str2.print();
return 0;
}
可以编译,结果为:
learnc++
learnc++
learnjava
learnjava
除此之外,还有:
*** Error in `./code': double free or corruption (fasttop): 0x0000000000f7f010 ***
BTY,如果我在String::change中删除"delete [] s;",结果就变成了:
learnc++
learnc++
learnc++
learnjava
没有出现错误,为什么?
代码来自geek foe feeks,我更改了一些字符串,并且代码在其IDE中可以是运行,但在我的ubuntu 14.04中,它不能。
您的 class 不遵循 Rule of Three 因为它缺少正确的复制构造函数。
String str2 = str1;
只是 String str2(str1);
的语法糖,所以它使用复制构造函数,而不是你的 operator=
(它有内存泄漏,顺便说一句)。
由于你没有提供复制构造函数,编译器为你提供了一个,但它没有对char*
数据进行深度复制。它只是复制指针本身,这会导致您看到的行为。
正确的实现看起来更像这样:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL);
String(const String &src);
~String();
String& operator=(const String &rhs);
void print() const;
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
String::String(const String &src)
{
size = src.size;
s = new char[size+1];
strcpy(s, src.s);
}
String::~String()
{
delete [] s;
}
void String::print() const
{
cout << s << endl;
}
String& String::operator=(const String &rhs)
{
if (&rhs != this)
{
String tmp(rhs);
swap(s, tmp.s);
swap(size, tmp.size);
}
return *this;
}
int main()
{
String str1("learnc++");
String str2 = str1;
str1.print();
str2.print();
//str2.change("learnjava");
str2 = "learnjava";
str1.print();
str2.print();
return 0;
}
如果您使用的是 C++11 或更高版本,则可以改用此实现,它通过添加移动语义遵循五法则:
#include <iostream>
#include <cstring>
#include <utility>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = nullptr);
String(const String &src);
String(String &&src);
~String();
String& operator=(String rhs);
void print() const;
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
String::String(const String &src)
{
size = src.size;
s = new char[size+1];
strcpy(s, src.s);
}
String::String(String &&src)
{
size = src.size;
s = src.s;
src.s = nullptr;
src.size = 0;
}
String::~String()
{
delete [] s;
}
void String::print() const
{
cout << s << endl;
}
String& String::operator=(String rhs)
{
swap(s, rhs.s);
swap(size, rhs.size);
return *this;
}
添加复制构造函数。
String(const String& c){
size = strlen(c.s);
s = new char[size+1];
strcpy(s, c.s);
}
这是我的代码:
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
String& operator=(String &c){
size = strlen(c.s);
s = new char[size+1];
strcpy(s, c.s);
}
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
void String::change(const char *str)
{
delete [] s;
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
int main()
{
String str1("learnc++");
String str2 = str1;
str1.print(); // what is printed ?
str2.print();
str2.change("learnjava");
str1.print(); // what is printed now ?
str2.print();
return 0;
}
可以编译,结果为:
learnc++
learnc++
learnjava
learnjava
除此之外,还有:
*** Error in `./code': double free or corruption (fasttop): 0x0000000000f7f010 ***
BTY,如果我在String::change中删除"delete [] s;",结果就变成了:
learnc++
learnc++
learnc++
learnjava
没有出现错误,为什么? 代码来自geek foe feeks,我更改了一些字符串,并且代码在其IDE中可以是运行,但在我的ubuntu 14.04中,它不能。
您的 class 不遵循 Rule of Three 因为它缺少正确的复制构造函数。
String str2 = str1;
只是 String str2(str1);
的语法糖,所以它使用复制构造函数,而不是你的 operator=
(它有内存泄漏,顺便说一句)。
由于你没有提供复制构造函数,编译器为你提供了一个,但它没有对char*
数据进行深度复制。它只是复制指针本身,这会导致您看到的行为。
正确的实现看起来更像这样:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL);
String(const String &src);
~String();
String& operator=(const String &rhs);
void print() const;
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
String::String(const String &src)
{
size = src.size;
s = new char[size+1];
strcpy(s, src.s);
}
String::~String()
{
delete [] s;
}
void String::print() const
{
cout << s << endl;
}
String& String::operator=(const String &rhs)
{
if (&rhs != this)
{
String tmp(rhs);
swap(s, tmp.s);
swap(size, tmp.size);
}
return *this;
}
int main()
{
String str1("learnc++");
String str2 = str1;
str1.print();
str2.print();
//str2.change("learnjava");
str2 = "learnjava";
str1.print();
str2.print();
return 0;
}
如果您使用的是 C++11 或更高版本,则可以改用此实现,它通过添加移动语义遵循五法则:
#include <iostream>
#include <cstring>
#include <utility>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = nullptr);
String(const String &src);
String(String &&src);
~String();
String& operator=(String rhs);
void print() const;
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
String::String(const String &src)
{
size = src.size;
s = new char[size+1];
strcpy(s, src.s);
}
String::String(String &&src)
{
size = src.size;
s = src.s;
src.s = nullptr;
src.size = 0;
}
String::~String()
{
delete [] s;
}
void String::print() const
{
cout << s << endl;
}
String& String::operator=(String rhs)
{
swap(s, rhs.s);
swap(size, rhs.size);
return *this;
}
添加复制构造函数。
String(const String& c){
size = strlen(c.s);
s = new char[size+1];
strcpy(s, c.s);
}