gpt4 book ai didi

c++ - 为什么这个对象没有按值复制

转载 作者:行者123 更新时间:2023-11-30 02:40:18 26 4
gpt4 key购买 nike

当我在 operator* 函数中返回对象 temp 时,它没有被复制到 main 中的 p3。

operator* 函数内的 cout 语句返回正确的值,但 main 中的 p3 只有垃圾。

此外,我在 main 的 return 0 语句中得到一个 _block_type_is_valid(phead->nblockuse)。

这是代码。

#pragma once
#include<iostream>
using namespace std;
class Polynomial
{
private:
int *coefficients;
int length;
public:
inline int getLength() const {return length;}
Polynomial(int length);
Polynomial(const Polynomial &p);
Polynomial():coefficients(nullptr){}
~Polynomial(void);
extern friend Polynomial operator*(const Polynomial &p1,const Polynomial &p2);
inline int operator[](int n) const { return coefficients[n];}
inline int& operator[](int n) { return coefficients[n];}
Polynomial& operator=(Polynomial &p);
friend void swap(Polynomial& first, Polynomial& second);
void resize(int x);

friend istream& operator>>(istream &is, Polynomial &p);
friend ostream& operator<<(ostream &os, Polynomial &p);
};

这里是多项式.cpp

#include "Polynomial.h"

Polynomial::Polynomial(int length){
this->length = length;
coefficients = new int[length];
for(int i = 0; i < length; i++){
coefficients[i] = 0;
}
}


Polynomial::~Polynomial(void){
cout<<"Deleting: "<<coefficients;
delete[] coefficients;
}
/*
Polynomial Polynomial::operator*(Polynomial p){
Polynomial temp(length + p.getLength());

for(int i = 0; i < length; i++){
for(int j = 0; j < length; j++){
temp[i+j] += coefficients[i] * p[j];
}
}
cout<<temp;
return temp;
}*/

Polynomial operator*(const Polynomial &p1,const Polynomial &p2){
Polynomial temp(p1.getLength() + p2.getLength());

for(int i = 0; i < p1.getLength(); i++){
for(int j = 0; j < p2.getLength(); j++){
temp[i+j] += p1[i] * p2[j];
}
}
cout<<temp;
return temp;
}
void Polynomial::resize(int x){
delete[] coefficients;
coefficients = new int[x];
}
void swap(Polynomial& first,Polynomial& second){
int tempLength = first.getLength();
int *temp = new int[tempLength];
for(int i = 0; i < first.getLength(); i++)
temp[i] = first[i];
first.resize(second.getLength());
for(int i = 0; i < first.getLength(); i++)
first[i] = second[i];
second.resize(tempLength);
for(int i = 0; i < first.getLength(); i++)
second[i] = temp[i];
delete[]temp;
}
Polynomial& Polynomial::operator=(Polynomial &p){
swap(*this,p);
return *this;
}
Polynomial::Polynomial(const Polynomial &p){
//if(coefficients) delete [] coefficients;
coefficients = new int[p.getLength()];
for(int i = 0; i < p.getLength(); i++)
coefficients[i] = p[i];
}
istream& operator>>(istream &is,Polynomial &p){
cout<<"Enter length: ";
is>>p.length;
p.coefficients = new int[p.length];
for(int i = 0; i < p.length; i ++)
is>>p.coefficients[i];
return is;
}
ostream& operator<<(ostream &os,Polynomial &p){
for(int i = 0; i < p.length; i ++)
if(p.coefficients[i])
os<<p.coefficients[i]<<"x^"<<i<<" ";
return os;
}

这是主要的

#include"Polynomial.h"

#include<iostream>
#include<string>

using namespace std;

int main(){
Polynomial p1,p2,p3;
cin>>p1>>p2;
p3 = (p1 * p2);
cout<<p3[0]<<p3[1]<<"here";
cout<<p3;

return 0;
}

编辑:这是最终更正后的代码。我需要做的就是在所有构造函数中将指针初始化为 null 并将长度初始化为 0。

#include "Polynomial.h"

Polynomial::Polynomial():
coefficients(nullptr),length(0){}

Polynomial::Polynomial(int length):coefficients(nullptr),length(length){
coefficients = new int[length];
for(int i = 0; i < length; i++){
coefficients[i] = 0;
}
}

Polynomial::~Polynomial(void){
if(coefficients) delete[]coefficients;
}

Polynomial& Polynomial::operator=(const Polynomial &p){
if(coefficients)
delete[]coefficients;

length = p.getLength();
coefficients = new int[length];
for(int i = 0; i < length; i++)
coefficients[i] = p[i];

return *this;
}
Polynomial::Polynomial(const Polynomial &p):
coefficients(nullptr),length(0)
{
length = p.getLength();
coefficients = new int[length];
for(int i = 0; i < length; i++)
coefficients[i] = p[i];
}

Polynomial operator*(const Polynomial &p1,const Polynomial &p2){
Polynomial temp(p1.getLength() + p2.getLength());
for(int i = 0; i < p1.getLength(); i++)
for(int j = 0; j < p2.getLength(); j++)
temp[i+j] += p1[i] * p2[j];
return temp;
}

istream& operator>>(istream &is,Polynomial &p){
cout<<"Enter length: ";
is>>p.length;
p.coefficients = new int[p.length];
for(int i = 0; i < p.length; i ++)
is>>p.coefficients[i];
return is;
}
ostream& operator<<(ostream &os,Polynomial &p){
for(int i = 0; i < p.length; i ++)
if(p.coefficients[i])
os<<p.coefficients[i]<<"x^"<<i<<" ";
return os;
}

最佳答案

如果您使用正确的标志调用编译器,则此代码不能编译。 没有可以很好地使用默认标志的 C++ 编译器!

例如,让我们以 Visual C++ 2013 为例,像这样调用,带有一些非默认标志:

cl /nologo /EHsc /Za /W4 stackoverflow.cpp

正确的结果是编译器错误:

stackoverflow.cpp(78) : error C2679: binary '=' : no operator found which takes a right-hand operand of type 'Polynomial' (or there is no acceptable conversion)

stackoverflow.cpp(19): could be 'void Polynomial::operator =(Polynomial &)'
while trying to match the argument list '(Polynomial, Polynomial)'

现在让我们看看如果我们删除禁用 Microsoft 扩展的 /Za 标志会发生什么:

cl /nologo /EHsc /W4 stackoverflow.cpp

错误消失了。但是,会出现一个警告:

warning C4239: nonstandard extension used : 'argument' : conversion from 'Polynomial' to 'Polynomial &'
A non-const reference may only be bound to an lvalue; assigment operator takes a reference to non-const

最后,让我们看看如果我们删除警告级别标志 /W4 编译器会做什么:

cl /nologo /EHsc stackoverflow.cpp

没有错误,没有警告。那是不好的p3 = (p1 * p2); 不是标准的 C++。即使您可以让 Visual C++ 编译代码,也不会产生任何好处。

赋值运算符的正确签名是:

Polynomial& Polynomial::operator=(Polynomial const& p);

然而,您的代码的最大问题是 new[]delete[] 的使用。你肯定在某处有内存泄漏(构造和赋值都分配,但只有析构函数删除),更糟糕的是,你多次删除同一个数组。

将以下输出添加到您的析构函数:

Polynomial::~Polynomial(void){
std::cout << "coefficients address destructor: " << coefficients << "\n";
delete[] coefficients;
}

如果你现在运行它,你会看到如下内容:

Enter length: 2
100
200
Enter length: 3
100
200
300
10000x^0 40000x^1 40000x^2 coefficients address destructor: 00463BF8
coefficients address destructor: 00463BF8
1040000herecoefficients address destructor: 00463BF8

三次 00463BF8!这是未定义的行为,可能导致您的程序中发生所有可以想象的事情。

但这怎么可能呢?

答案是您的operator* 返回Polynomial 对象的浅表拷贝。里面的指针被复制,你最终得到两个指向相同分配内存的指针。

您需要一个复制构造函数。并且您必须遵守所谓的三原则:如果您需要实现复制构造函数、复制赋值运算符和析构函数中的一个,那么您需要实现它们所有 .

尽管如此,与其不厌其烦地手动实现带有无数陷阱的动态分配,不如帮自己一个忙,使用 std::vector 代替指针和长度变量:

class Polynomial
{
private:
std::vector<int> coefficients;
// ...
};

您的下标运算符也需要修改。事实上,您将需要其中两个,一个用于 const 访问,一个用于非常量访问:

inline int operator[] (int n) const { return coefficients[n];}
inline int& operator[] (int n) { return coefficients[n];}

参见 why do subscript operators C++ often comes in pair?

最后,我认为你误解了extern。您不需要它来使用 friend 函数。只需将其从您的代码中删除即可;否则 GCC 甚至不会编译它。

这是一个包含最重要修复的完整示例:

#include <iostream>
#include <vector>

using namespace std;

class Polynomial
{
private:
std::vector<int> coefficients;
public:
inline int getLength() const {return coefficients.size();}
Polynomial(int length);
Polynomial(){}
Polynomial operator*(Polynomial &p);
inline int operator[] (int n) const { return coefficients[n];}
inline int& operator[] (int n) { return coefficients[n];}

friend istream& operator>>(istream &is, Polynomial &p);
friend ostream& operator<<(ostream &os, Polynomial &p);
};

Polynomial::Polynomial(int length) :
coefficients(length)
{
for(int i = 0; i < length; i++){
coefficients[i] = 0;
}
}

Polynomial Polynomial::operator*(Polynomial &p){
Polynomial temp(coefficients.size() + p.getLength());

for(int i = 0; i < coefficients.size(); i++){
for(int j = 0; j < coefficients.size(); j++){
temp[i+j] += coefficients[i] * p[j];
}
}
cout<<temp;
return temp;
}

istream& operator>>(istream &is,Polynomial &p){
cout<<"Enter length: ";
int length;
is>>length;
p.coefficients.clear();
p.coefficients.resize(length);
for(int i = 0; i < length; i ++)
is>>p.coefficients[i];
return is;
}
ostream& operator<<(ostream &os,Polynomial &p){
for(int i = 0; i < p.coefficients.size(); i ++)
if(p.coefficients[i])
os<<p.coefficients[i]<<"x^"<<i<<" ";
return os;
}

int main(){
Polynomial p1,p2,p3;
cin>>p1>>p2;
p3 = (p1 * p2);

cout<<p3[0]<<p3[1]<<"here";
cout<<p3;

return 0;
}

您不再需要自己编写的复制构造函数、复制赋值运算符或析构函数,因为 std::vector 知道如何以安全的方式复制、赋值和析构自身级内存问题。

进一步改进的示例:

  • 检查 std::cin 是否实际收到有效整数。
  • 根据 operator*= 实现 operator*
  • operator* 接受一个 const 引用。
  • 不要在头文件的全局范围内使用using namespace

通常,阅读const 和运算符重载的最佳实践。

关于c++ - 为什么这个对象没有按值复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29047717/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com