C++ 中重载 = 运算符当有要复制的值数组时
我对 C++ 有点陌生,所以我想这是一个非常基本的问题。
假设我有这个类:
// file Graph.h
class Graph {
public:
Graph(int N); // contructor
~Graph(); // destructor
Graph& operator=(Graph other);
private:
int * M;
int N;
};
// file Graph.cpp
Graph :: Graph(int size) {
M = new int [size];
N = size;
}
Graph :: ~Graph() {
delete [] M;
}
我想创建一个赋值运算符,它将复制数组 M[] 的内容,但当我在复制后更改它时不覆盖它(我认为这是通过不复制实际指针而仅复制内容来完成的,不知道我是否正确)。这是我尝试过的:
Graph& Graph::operator=(Graph other) {
int i;
N = other.N;
M = new int [N];
for (i = 0; i < N; i++)
M[i] = other.M[i];
return *this;
}
这是正确的吗?还有其他方法可以做到这一点吗?
编辑:我忘记了一个重要的问题。为什么我必须像 Graph& 那样声明它operator=(Graph other); 而不仅仅是: Graph operator=(Graph other);
这是我的书(C++: The Complete Reference,第二版,Herbert Schildt,第 355-357 页)?
I'm somewhat new to C++ so, I guess this is a very basic question.
Suppose I have this class:
// file Graph.h
class Graph {
public:
Graph(int N); // contructor
~Graph(); // destructor
Graph& operator=(Graph other);
private:
int * M;
int N;
};
// file Graph.cpp
Graph :: Graph(int size) {
M = new int [size];
N = size;
}
Graph :: ~Graph() {
delete [] M;
}
I want to create an assignment operator that will copy the contents of array M[] but not to overwrite it when I change it after the copy (I think this is accomplished by not copying the actual pointer but only the content, don't know if I'm right). This is what I've tried:
Graph& Graph::operator=(Graph other) {
int i;
N = other.N;
M = new int [N];
for (i = 0; i < N; i++)
M[i] = other.M[i];
return *this;
}
Is this correct? Are there other ways to do this?
edit: An important question I forgot. Why I must declare it like Graph& operator=(Graph other);
and not just: Graph operator=(Graph other);
which is what's written in my book (C++: The Complete Reference, 2nd ed, Herbert Schildt, pages 355-357)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
规范的方法是使用
std::vector
来避免自己管理内存。不过,对于这个练习,做你想做的事情的正确方法是:谷歌“复制和交换习惯用法”来了解代码背后的基本原理。请注意,您的分配运算符会泄漏内存(原始数组被覆盖但从未删除),如果分配失败,您最终会得到一个损坏的对象。此外,
x = x
不会执行预期的操作。这三个陷阱很常见,以复制和交换方式编写赋值运算符可以避免它们。编辑:对于您的其他问题,返回引用允许您链接赋值,例如
a = b = c
,这对于内置类型有效。它可能是也可能不是您想要的(通常是)。The canonical way is to use a
std::vector<int>
to avoid managing memory yourself. For the exercise though, the right way to do what you want is:Google "copy and swap idiom" for the rationale behind the code. Note that your assigment operator leaks memory (the original array is overwritten but never deleted) and if the allocation fails, you end up with a broken object. Moreover,
x = x
won't do what it is expected to do. These three pitfalls are common, and writing assignment operators in copy-and-swap style avoids them.EDIT: For your other question, returning a reference allows you to chain assignments, like
a = b = c
, which is valid for built in types. It may or may not be what you want (it usually is).您需要
operator=
中的&
,以便在返回*this
时不会导致复制。更重要的问题是为什么你需要退货。答案是支持a=b=c
语法。我建议您将 memcpy 用于内置 int 类型(或指针)的标准数组。该标准的定义方式为编译器编写者提供了一种提供最快的、特定于平台的实现的方法。
如果类型是对象,请勿使用 memcpy (不会调用复制构造函数和许多其他不好的事情)
You need the
&
inoperator=
so that it doesn't cause a copy when you return*this
. The more important question is why do you need to return anything. The answer is to supporta=b=c
syntax.I would suggest you use memcpy for standard arrays of built-in int-like types (or pointers). The standard defines it in a way that gives the compiler writer a way to provide the fastest possible, platform-specific implementation.
Do not use memcpy if the type is an object (won't call copy constructor and a lot of other bad things)
您可能想要声明并定义一个复制构造函数。
事实上,在您的情况下这是必须的,因为默认的复制构造函数将在销毁期间导致双重
删除
。我认为在赋值运算符中使用复制构造函数(复制构造后跟交换)更惯用。
至于当前代码,存在内存泄漏(因为旧的
M
没有delete
d)。You'd probably want to declare and define a copy constructor.
In fact, it is a must in your situation because the default copy constructor will result in a double
delete
during destruction.I think it's more idiomatic to use the copy constructor in the assignment operator (a copy construction followed by a swap).
As for the current code, there is a memory leak (because the old
M
is notdelete
d).其中一些已经被其他人说过,但是如果我们想坚持使用您拥有的基本布局,您应该更改此设置:
哦顺便说一句。您不必通过在函数开头声明“i”来使用 C 语法 -> “for(int i =....”
希望有帮助:)
Some of it have already been said by others, but if we want to stick with basic layout that you have, you should change this:
Oh btw. You don´t have to use C syntax by declaring "i" in the start of the function -> "for(int i =...."
Hope it helped :)
差不多都说了,但是有几个重要的注意事项:
const Graph&其他
,以避免大量复制到临时对象(除非您使用 “复制和交换”习语这个页面可能会有所帮助。全面:C++ 运算符重载指南
almost all have been said, but there are a few important notes:
const Graph& other
, to avoid heavy copying to a temp object (unless you are using a "copy and swap" idiomstd::vector
? will save you all this trouble without noticeable performance penalty.this page may be helpful - simple and comprehensive: C++ Operator Overloading Guidelines
您还可以在此处使用 std::copy 更多 std::copy
或者您可以< code>memcpy 数组也是如此
You could also use std::copy more here std::copy
or you can
memcpy
arrays as well不要忘记编写
graph_a = graph_a
; 是合法的。您的代码将泄漏最初分配给graph_a.M
的内存,并且在复制后您将在M
中得到未初始化的内存。在进行复制分配之前,您必须检查是否没有将同一对象复制到其自身之上(在这种情况下您可以直接返回)。
Don't forget that it's legal to write
graph_a = graph_a
; your code will leak the memory originally allocated forgraph_a.M
, and you'll end up with uninitialised memory inM
after the copy.Before doing a copy-assignment, you must check that you're not copying the same object over itself (in which case you can just return).
您必须返回对已构造的对象的引用。如果您返回了一个副本,那么您将继续复制构造另一个对象,并丢弃您已经拥有的对象。
You must return a reference to the object that you have constructed. If you returned a copy, you would then proceed to copy construct another object, discarding the one that you already have.