点的复制构造函数
Copy constructor for point
这个复制构造函数正确吗?
class GPSPoint
{
private:
double lat, lon, h;
char *label;
public:
GPSPoint (const GPSPoint &p)
{
if (this != &p)
{
lat = p.lat;
lon = p.lon;
h = p.h;
if ( label != NULL )
{
delete [] label;
label = NULL;
}
if (p.label != NULL )
{
label = new char [ strlen( p.label ) + 1 ];
strcpy ( label, p.label );
}
}
}
}
如果你在你的类中有一个指针,你可能做错了什么
最好重写为:
class GPSPoint
{
private:
double lat;
double lon;
double h;
std::string label;
public:
GPSPoint (GPSPoint const& copy)
: lat(copy.lat)
, lon(copy.lon)
, h(copy.h)
, label(copy.label)
{}
// You should also have an assignment operator
GPSPoint& operator=(GPSPoint copy) // Use Copy/Swap idum.
{ // Pass by value to get implicit copy
this->swap(copy); // Now swap
return *this;
}
void swap(GPSPoint& copy) throw()
{
std::swap(lat, copy.lat);
std::swap(lon, copy.lon);
std::swap(h, copy.h);
std::swap(label,copy.label);
}
};
现在看起来简单多了。
但是我们忘了还有编译器生成的复制构造函数:
所以它现在也简化了:
class GPSPoint
{
private:
double lat;
double lon;
double h;
std::string label;
};
。
如果你必须绝对保留指针(因为你认为这是一个优化(它不是),或者你需要学习指针(你做,但你需要学习什么时候不使用它们)。
class GPSPoint
{
private:
double lat;
double lon;
double h;
char* label;
public:
// Don't forget the constructor and destructor should initialize label
// Note the below code assumes that label is never NULL and always is a
// C-string that is NULL terminated (but that each copy creates
// and maintains its own version)
GPSPoint (GPSPoint const& copy)
: lat(copy.lat)
, lon(copy.lon)
, h(copy.h)
, label(new char[strlen(copy.label)+1])
{
std::copy(copy.label, copy.label + strlen(label) + 1, label);
}
// You should also have an assignment operator
GPSPoint& operator=(GPSPoint copy) // Use Copy/Swap idum.
{ // Pass by value to get implicit copy
this->swap(copy); // Now swap
return *this;
}
void swap(GPSPoint& copy) throw()
{
std::swap(lat, copy.lat);
std::swap(lon, copy.lon);
std::swap(h, copy.h);
std::swap(label,copy.label);
}
};
这有点啰嗦;我会重新设计它的样式。
更重要的是,它看起来更像一个op=
而不是一个复制构造函数,特别是因为您测试label
是否为NULL
,就好像它已经可以使用一样。而且,由于它没有初始化,它不太可能已经是NULL
了……delete [] label
是一个严重错误。
但是如果你把这个作为你的op=
,那么我想这在语义上是正确的。
所以不要忘记你的构造函数(并将label
初始化为NULL
!),复制构造函数(让它使用op=
)和析构函数。
我知道你在之前的问题中说过(没有任何令人信服的理由)你"不想使用std::string
",但这是一个很好的例子,说明为什么你真的应该使用。
在我的理解中,您创建了operator =
的有效实现,而不是复制构造函数。如果对象已经存在,则if (this != &p)
有意义;对于删除标签
简而言之:不。这不是一个可怕的赋值操作符,但它作为复制构造函数是坏的。
首先,不可能发生自赋值,因为您没有赋值任何东西。this
指向构造函数开始时未初始化的内存blob,而p
是正在复制的完全构造的Point对象。这两者不能同时发生。因此,初始检查是浪费时间。
再往下,检查确保label
不为空。正如我所说,this
指向未初始化的内存…此时label
可以是任何值,不知道测试是否会通过或失败。如果它不产生空,你将delete[]
一个随机的内存部分。如果幸运的话,这将立即失败,但它不必如此。
就风格而言,首选构造函数初始化列表来初始化成员。
GPSPoint (const GPSPoint& copy)
: lat(copy.lat)
, lon(copy.lon)
, h(copy.h)
, label(0)
{
if(copy.label) {
label = new char[ strlen( copy.label ) + 1 ];
strcpy ( label, copy.label );
}
}
在正确性方面,去掉c-string,使用合适的string类。这样,你就根本不需要实现复制构造函数了。
无论如何,如果要实现复制构造函数,请确保实现复制赋值操作符和析构函数;我想这些是为了简洁而省略的,但如果不是的话,它们是非常重要的。
正如a1ex07在注释中所说,您的代码看起来更像是放在operator=
中的代码,而不是放在复制构造函数中。
首先,复制构造函数初始化了一个全新的对象。像if (this != &p)
这样的检查在复制构造函数中没有多大意义;你传递给复制构造函数的点永远不会是你在那一点初始化的对象(因为它是一个全新的对象),所以检查总是true
。
同样,做if (label != NULL)
这样的事情是行不通的,因为label
还没有初始化。此检查可能以随机方式返回true
或false
(取决于未初始化的label
是否碰巧是NULL
)。
我会这样写:
GPSPoint(const GPSPoint& p) : lat(p.lat), lon(p.lon), h(p.h) {
if (p.label != NULL) {
label = new char[strlen(p.label) + 1];
strcpy(label, p.label);
}
else {
label = NULL;
}
}
也许让label
成为std::string
而不是c风格的char*
会是一个更好的主意,然后你可以纯粹使用初始化列表来编写复制构造函数:
class GPSPoint {
private:
double lat, lon, h;
std::string label;
public:
// Copy constructor
GPSPoint(const GPSPoint& p) : lat(p.lat), lon(p.lon), h(p.h), label(p.label) { }
}
是的——我最初读错了。
但是,我仍然建议您使用std::string
作为标签,因为它将为您管理内存,并且复制构造函数变得更简单(实际上,在这种情况下是不必要的)。
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 使用复制构造函数复制双精度数组
- C 无可行的构造函数复制类型的变量
- 没有可行的构造函数复制类型 'MyString' 的数组元素
- 编译时,复制构造函数/复制分配和正常功能调用优化之间是否存在任何区别
- 如何最小化调用列表构造函数(复制构造函数)的次数?
- C 11矢量构造函数复制与范围
- 我定义了一个非复制构造函数;复制构造函数还会被隐式定义吗
- 可以将构造函数复制为转换运算符
- 将基类指针的构造函数复制到子类
- C++树类:构造函数/复制/内存泄漏
- 如何制作这个在模板构造函数复制中使用类型定义的类型的模板
- 将构造函数复制为模板化的成员函数
- 绕过私有复制构造函数/复制赋值C++
- C++通过构造函数复制对象
- 复制构造函数 - 复制C++中的对象
- 将带unique_ptr的类的构造函数复制到作为成员的抽象类