我对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,2nd ed,Herbert Schildt,355-357页)?
答案 0 :(得分:9)
规范的方法是使用std::vector<int>
来避免自己管理内存。但是,对于练习来说,做正题的正确方法是:
#include <algorithm>
class Graph
{
public:
Graph(size_t n) { data_ = new int[n](); size_ = n; }
Graph(Graph const& g)
{
data_ = new int(g.size_);
size_ = g.size_;
std::copy(g.data_, g.data_ + g.size_, data_);
}
~Graph() { delete[] data_; }
void swap(Graph& g) throw()
{
std::swap(data_, g.data_);
std::swap(size_, g.size_);
}
Graph& operator=(Graph g) { g.swap(*this); return *this; }
private:
int* data_;
size_t size_;
};
Google“复制和交换习惯用法”代码背后的理由。请注意,您的分配运算符会泄漏内存(原始数组会被覆盖,但永远不会被删除),如果分配失败,最终会导致对象损坏。而且,x = x
不会做预期的事情。这三个陷阱很常见,以复制交换方式编写赋值运算符可以避免它们。
编辑:对于您的其他问题,返回引用允许您链接分配,如a = b = c
,这对内置类型有效。它可能是也可能不是你想要的(通常是)。
答案 1 :(得分:3)
您需要&
中的operator=
,以便在您返回*this
时不会导致副本。更重要的问题是为什么你需要退货。答案是支持a=b=c
语法。
我建议你使用memcpy作为内置类int(或指针)的标准数组。该标准以一种方式定义它,使编译器编写者能够提供尽可能快的,特定于平台的实现。
如果类型是对象(不会调用复制构造函数和许多其他坏东西),请不要使用memcpy。
答案 2 :(得分:1)
您可能想要声明并定义复制构造函数。
事实上,在您的情况下这是必须的,因为默认的复制构造函数在销毁期间将导致双delete
。
我认为在赋值运算符中使用复制构造函数更为惯用(复制构造后跟交换)。
对于当前代码,存在内存泄漏(因为旧的M
不是delete
d)。
答案 3 :(得分:1)
几乎所有人都说过,但有一些重要的注意事项:
const Graph& other
,以避免大量复制到临时对象(除非您使用{{ 3}} std::vector
?将为您节省所有这些麻烦而不会有明显的性能损失。此页面可能会有所帮助 - 简单而全面:"copy and swap" idiom
答案 4 :(得分:1)
其他人已经说过其中一些,但如果我们想坚持你所拥有的基本布局,你应该改变这个:
希望它有所帮助:)
答案 5 :(得分:0)
你也可以在这里使用std :: copy std::copy
或者你也可以memcpy
数组
答案 6 :(得分:0)
不要忘记写graph_a = graph_a
是合法的;您的代码将泄漏最初为graph_a.M
分配的内存,并且在复制后您将在M
中获得未初始化的内存。
在进行复制分配之前,您必须检查您是否未将相同的对象复制到自身上(在这种情况下,您可以返回)。
答案 7 :(得分:0)
您必须返回对已构造对象的引用。如果您返回了副本,则您将继续复制构造另一个对象,丢弃您已有的对象。