点的复制构造函数
这个复制构造函数正确吗?
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 );
}
}
}
}
Is this copy constructor correct?
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 );
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果你的类中有一个指针,那么你可能做错了什么。
最好将其重写为:
现在看起来简单多了。
但是我们忘记了编译器生成的复制构造函数:
所以现在也简化了:
完成。越简单越好。
如果你必须绝对保留指针(因为你认为这是一种优化(其实不是),或者你需要学习指针(你确实这样做,但你需要学习何时不使用它们))。
If you have a pointer in your class you are probably doing something wrong.
It would be better to re-write it as:
Now that looks a lot simpler.
But hey we forgot there are compiler generated copy constructors:
So it now simplifies too:
Done. The simpler the better.
If you must absolutely keep the pointer (because you think it is an optimization (its not), or you need to learn pointers (you do, but you need to learn when not to use them)).
有点啰嗦;我会重新设计它的风格。
更重要的是,它看起来更像是
op=
而不是复制构造函数,特别是因为您测试label
的NULL
性,就好像它本来可以是已经用过。而且,由于它尚未初始化,它不太可能已经是NULL
...delete [] label
是一个严重错误。但是如果你把它作为你的
op=
,那么我想这在语义上是正确的。因此,不要忘记您的构造函数(并将
label
初始化为NULL
!)、复制构造函数(使其使用op=
)和析构函数。我知道您在上一个问题中说过(没有任何令人信服的理由)您“不想使用 std::string”,但这是一个完美的例子,说明了为什么您确实应该使用。
It's a bit verbose; I'd re-style it.
More importantly, it looks more like an
op=
than a copy constructor, especially because you testlabel
forNULL
ness as if it could have been used already. And, since it's not initialised, it's unlikely to beNULL
already...delete [] label
is then a critical error.But if you made this your
op=
, then I guess that would be semantically correct.So then don't forget your constructor (and initialise
label
toNULL
!), copy constructor (make it useop=
) and destructor.I know you stated in your previous question (without any convincing rationale) that you "don't want to use
std::string
", but this is a perfect example of why you really should.根据我的理解,您创建了
operator =
的有效实现,而不是复制构造函数。if (this != &p)
如果对象已经存在则有意义;删除标签也是如此In my understanding you created a valid implementation of
operator =
, not a copy constructor.if (this != &p)
makes sense if the object already exists ; the same for deleting label简而言之:不。这不是一个可怕的赋值运算符,但它作为复制构造函数被破坏了。
首先,不可能发生自分配,因为您没有分配任何东西。
this
指向构造函数开头处未初始化的内存块,而p
是您正在复制的完全构造的 Point 对象。两者不能重合。所以最初的检查是浪费时间。再往下,您检查以确保
label
不为空。正如我所说,this
指向未初始化的内存...此时label
可以是任何值,无法判断该测试是否会通过或失败。如果它确实产生不为空,您将删除[]
内存的随机部分。如果幸运的话,这会立即失败,但并非必须如此。就风格而言,更喜欢构造函数初始值设定项列表来初始化成员。
就正确性而言,摆脱 c 字符串,并使用适当的字符串类。然后,您根本不需要实现复制构造函数。
无论如何,如果您实现复制构造函数,请确保实现复制赋值运算符和析构函数;我认为这些内容是为了简洁而被省略的,但即使不是,它们也非常重要。
In short: no. That's not a horrible assignment operator, but it is broken as a copy constructor.
First, there is no possible way for self-assignment to occur, because you are not assigning anything.
this
points to an uninitialized blob of memory at the start of your constructor, whilep
is a fully constructed Point object that you are copying. The two can not coincide. So the initial check is a waste of time.Further down, you check to ensure
label
is not null. As I said,this
points to uninitialized memory...label
can be any value at this point, there is no telling whether or not that test will pass or fail. If it does yield not null, you are going todelete[]
a random part of memory. If you are lucky, this will fail immediately, but it doesn't have to.In terms of style, prefer constructor initializer lists for initializing members.
In terms of correctness, get rid of the c-string, and use a proper string class. Then, you won't need to implement a copy constructor at all.
No matter what, if you implement a copy constructor make sure you implement a copy assignment operator and a destructor; I assume those were left out for brevity, but if not they are terribly important.
正如 a1ex07 在评论中所说,您的代码看起来更像是放在
operator=
中的代码,而不是放在复制构造函数中的代码。首先,复制构造函数正在初始化一个全新的对象。像
if (this != &p)
这样的检查在复制构造函数中没有多大意义;您传递给复制构造函数的点永远不会是您在该点初始化的对象(因为它是一个全新的对象),因此检查始终为true
。此外,执行诸如
if (label != NULL)
之类的操作是行不通的,因为label
尚未初始化。此检查可能以随机方式返回true
或false
(取决于未初始化的label
是否偶然为NULL
)。我会这样写:
也许将
label
设为std::string
而不是 C 风格的char*
会是一个更好的主意,那么你可以纯粹使用初始化列表来编写复制构造函数:As a1ex07 says in a comment, your code looks more like what you would put in
operator=
than in a copy constructor.First of all, a copy constructor is initializing a brand new object. A check like
if (this != &p)
doesn't make much sense in a copy constructor; the point you are passing to the copy constructor is never going to be the object that you are initializing at that point (since it's a brand new object), so the check is always going to betrue
.Also, doing things like
if (label != NULL)
is not going to work, becauselabel
is not yet initialized. This check might returntrue
orfalse
in random ways (depending if the uninitializedlabel
isNULL
by chance).I would write it like this:
Maybe making
label
astd::string
instead of a C-stylechar*
would be a better idea, then you could write your copy constructor purely using an initializer list:是的——我最初读错了。
不过,我仍然建议您使用
std::string
作为标签,因为它会为您管理内存,并且复制构造函数变得更加简单(事实上,对于这种情况是不必要的)。Yes -- I originally read it incorrectly.
However, I still suggest you use
std::string
for the label, as it will manage the memory for you and the copy constructor becomes much simpler (in fact, unnecessary for this case).