提问人:Preetom Saha Arko 提问时间:2/24/2023 最后编辑:Preetom Saha Arko 更新时间:2/24/2023 访问量:142
在从函数返回期间,复制构造函数的目的是什么?[复制]
What is the purpose of copy constructor during return from a function? [duplicate]
问:
#include <iostream>
using namespace std;
class samp
{
int *p;
int len;
int idx; // idx denotes the number of elements currently in the array (allocated by p)
public:
samp()
{
len=0;
p=NULL;
idx=0;
cout<<"inside default constructor"<<endl;
}
samp(int len)
{
this->len=len;
p=new int[len];
idx=0;
cout<<"inside parameterized constructor, p="<<p<<endl;
}
samp(const samp &s)
{
len=s.len;
idx=s.idx;
p = new int[len];
for(int i=0;i<idx;i++){
p[i]=s.p[i];
}
cout<<"inside copy constructor, p="<<p<<endl;
}
~samp()
{
cout<<"inside destructor, clearing memory "<<p<<endl;
delete[] p;
p=NULL;
}
void insert(int a)
{
if(idx<len){ // if there is still some place left in the array
p[idx]=a;
idx++;
}
}
void print()
{
for(int i=0;i<idx;i++){
cout<<p[i]<<" ";
}
cout<<endl;
}
};
samp f()
{
samp s(3);
int a;
for(int i=0;i<3;i++){
cin>>a;
s.insert(a);
}
cout<<"now we will return an object from a function"<<endl;
return s;
}
int main()
{
samp s1;
cout<<"now we will try to return an object from a function"<<endl;
s1 = f();
cout<<"function returned"<<endl;
s1.print();
return 0;
}
我得到以下输出和双重释放错误,因为相同的内存被释放了两次。由于复制省略,此处未调用复制构造函数。
inside default constructor
now we will try to return an object from a function
inside parameterized constructor, p=0x5573aa164e80
now we will return an object from a function
inside destructor, clearing memory 0x5573aa164e80
function returned
0 0 -1441456112
inside destructor, clearing memory 0x5573aa164e80
由于没有调用复制构造函数,因此我也得到了垃圾值。
当我用作编译器标志时,会调用复制构造函数,但双倍内存释放错误仍然存在。我得到这样的输出:-fno-elide-constructors
inside default constructor
now we will try to return an object from a function
inside parameterized constructor, p=0x10c008
now we will return an object from a function
inside copy constructor, p=0x10c040
inside destructor, clearing memory 0x10c008
inside destructor, clearing memory 0x10c040
function returned
85 23 19
inside destructor, clearing memory 0x10c040
Codeblocks 以某种方式设法打印存储在释放内存中的值,但相同的内存被释放了两次,我想避免这种情况。
在函数返回期间,析构函数在这里被调用了两次,很可能是因为它破坏了函数 f 的本地对象 s 一次,然后破坏了复制对象。
如果我们重载 = 运算符,双倍自由的问题就会消失。
samp& operator=(const samp &s)
{
len=s.len;
idx=s.idx;
p = new int[len];
for(int i=0;i<idx;i++){
p[i]=s.p[i];
}
cout<<"assigning, new p="<<p<<endl;
return *this;
}
然后我得到这样的输出:
inside default constructor
now we will try to return an object from a function
inside parameterized constructor, p=0x6bc008
now we will return an object from a function
inside copy constructor, p=0x6bc040
inside destructor, clearing memory 0x6bc008
assigning, new p=0x6bc078
inside destructor, clearing memory 0x6bc040
function returned
85 23 19
inside destructor, clearing memory 0x6bc078
我的问题是,如果复制构造函数无法解决内存位置被释放两次的问题,为什么在从函数返回对象时还要调用它?此外,= 运算符重载和复制构造函数的代码几乎相同。重载 = 运算符如何解决问题?
如果我从函数返回一个对象,那么很有可能在函数调用后将其分配给另一个对象。那么,每次我们从函数返回具有动态分配内存的对象时,我们是否需要重载 = 运算符?
我知道 STL 向量。在这种情况下,我需要知道复制构造函数的行为。
答:
您正在混淆和混合复制构造函数和赋值运算符。必须定义两者才能获得正确的 RAII,并正确处理分配的内存。
s1 = f();
这将调用赋值运算符。正是缺少赋值运算符导致了此处的双重释放。复制构造函数与它完全无关。
您的复制构造函数做得很好。从函数返回时,非省略副本始终调用复制构造函数。如果省略了副本,则不会复制任何内容,因此不涉及复制构造函数。
但是,无论是否省略了副本,这始终会导致调用赋值运算符。这是将返回的值分配给现有对象。句点。这需要调用赋值运算符。当将一个对象分配给另一个对象时,复制构造函数完全无关紧要。未能实现它导致了双重免费。
评论
=
=
=
评论
std::vector<int> p;
default
void operator=(samp const&) = delete;
s1 = f();
返回值 和 its 被逐位复制到一个带有赋值运算符的新实例中,现在两个实例都指向内存上的相同地址。当到达析构函数时,这两个实例都将尝试释放该内存。赋值运算符不调用 copy-constructor。在这种情况下,您还需要重载赋值运算符。f()
p
p