即使是复制分配运算符也无法提供帮助
Even the Copy Assignment Operator can't assist
请帮我找出问题所在。我也遵循了三法则,并对代码进行了一些修改。
#include <iostream>
using namespace std;
class AStack {
public:
AStack();
AStack(int);
AStack(const AStack&);
~AStack();
AStack& operator = (const AStack& s);
void push(int);
int pop();
int top();
bool isEmpty();
void flush();
private:
int capacity ;
int* a;
int index = -1; // Index of the top most element
};
AStack::AStack() {
a = new int[25];
capacity = 25;
}
AStack::AStack(int size) {
a = new int[size];
capacity = size;
}
AStack::AStack(const AStack& s) {
capacity = s.capacity;
delete[] a; // To avoid memory leak
a = new int[capacity];
for (int i = 0; i < capacity; i++) {
a[i] = s.a[i];
}
index = s.index;
}
AStack::~AStack() {
delete[] a;
}
AStack& AStack::operator = (const AStack& s) {
capacity = s.capacity;
delete[] a; // To avoid memory leak
int* a = new int[capacity];
for (int i = 0; i < capacity; i++) {
a[i] = s.a[i];
}
index = s.index;
return *this;
}
void AStack::push(int x) {
if (index == capacity - 1) {
cout << "nnThe stack is full. Couldn't insert " << x << "nn";
return;
}
a[++index] = x;
}
int AStack::pop() {
if (index == -1) {
cout << "nnNo elements to popnn";
return -1;
}
return a[index--];
}
int AStack::top() {
if (index == -1) {
cout << "nnNo elements in the Stacknn";
return -1;
}
return a[index];
}
bool AStack::isEmpty() {
return (index == -1);
}
void AStack::flush() {
if (index == -1) {
cout << "nnNo elements in the Stack to flushnn";
return;
}
cout << "nnFlushing the Stack: ";
while (index != -1) {
cout << a[index--] << " ";
}
cout << endl << endl;
}
AStack& reverseStack(AStack& s1) {
AStack s2;
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
s1 = s2;
return s1;
}
int main() {
AStack s1;
s1.push(1);
s1.push(2);
s1.push(3);
s1.push(4);
s1.push(5);
s1 = reverseStack(s1);
cout << "nnFlushing s1:n";
s1.flush();
system("pause");
return 0;
}
我不明白即使在定义了适当的复制赋值运算符之后,从函数返回后 s1 中的值也是垃圾值。
如果你的复制构造函数是正确的,并且你的析构函数是正确的,你的赋值运算符可以以更简单、更安全的方式编写。
目前,赋值运算符有两个主要缺陷:
- 不检查自我分配。
this
在知道可以成功分配内存(您的代码不是异常安全的)。
出错的原因是对 reverseStack
的调用返回对当前对象的引用。 这将调用赋值运算符,因此赋值运算符将当前对象分配给当前对象。 因此,上述问题1
被触发。
然后重新分配自己,但是你从哪里得到循环中的值来分配? 它们被删除了,因此它们是垃圾。
对于上面的第 2
项,这些行会在分配内存之前更改this
:
capacity = s.capacity;
delete[] a; // To avoid memory leak
如果对new[]
的调用引发异常,会发生什么情况? 您不仅通过更改容量值弄乱了对象,而且还通过过早调用delete[]
销毁了对象中的数据。
另一个问题(需要修复以在答案后面使用复制/交换习惯用法)是你的复制构造函数正在释放它从未分配的内存:
AStack::AStack(const AStack& s) {
capacity = s.capacity;
delete[] a; // ?? What
删除带有delete[] a
的行,因为您很可能在指向垃圾的指针上调用delete[]
。
现在,为了摆脱赋值运算符的这些问题,应该使用复制/交换习惯用法。 这需要一个工作副本构造函数和一个工作析构函数,然后才能使用此方法。 这就是为什么我们需要在继续之前先修复您的复制构造函数。
#include <algorithm>
//...
AStack& AStack::operator = (AStack s)
{
std::swap(capacity, s.capacity);
std::swap(a, s.a);
std::swap(index, s.index);
return *this;
}
请注意,我们不需要检查自赋值,因为按值传递的对象是一个全新的临时对象,我们从中获取值,而不是当前对象的值(同样,这是原始代码失败的原因)。
此外,如果new[]
抛出异常,则在创建按值传递的临时对象时,将在调用赋值运算符时引发异常。 因此,我们永远不会有机会因为抛出异常而无意中弄乱我们的对象new[]
。
请阅读copy/swap
习语是什么,以及为什么这是编写赋值运算符的最简单、最安全和最可靠的方法。 这个答案详细解释了你需要知道什么:
什么是复制和交换成语?
下面是固定代码的实时示例。 请注意,还有其他更改,例如删除默认构造函数并使Attack(int)
析构函数采用默认参数 25。
现场示例:http://ideone.com/KbA20D
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 使用strcpy将char数组的元素复制到另一个数组
- 是否可以初始化不可复制类型的成员变量(或基类)
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 需要帮助设置在C++中使用的Potrace
- 复制列表初始化的隐式转换的等级是多少
- 在指针的帮助下,文本文件中单词的频率
- 当从函数参数中的临时值调用复制构造函数时
- 有可能在Armadillo中复制MATLAB circshift方法吗
- 复制几乎为空的数组的最快方法
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 以下示例中如何避免代码复制?C++/库达
- C 指针节点帮助 - 将参数复制到链接的列表节点更改该节点的不同部分
- C 帮助复制构造函数
- 需要帮助将c字符串从嵌入式SQL提取复制到单独结构中的另一个c字符串
- 即使是复制分配运算符也无法提供帮助
- 动态数组:需要帮助将一个数组复制到另一个数组
- 动态数组,析构函数,深度复制需要帮助