C++ 复制构造函数:何时释放存储?
鉴于代码:C++ 复制构造函数:何时释放存储?,c++,copy-constructor,C++,Copy Constructor,鉴于代码: class Sample { public: int *ptr; Sample(int i) { ptr = new int(i); } ~Sample() { delete ptr; } void PrintVal() { cout << "The value is " << *ptr; } };
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
}
我不明白为什么会出现第二行输出。输出的第二行。我认为编译器在没有显式指定的情况下提供了一个副本构造函数。因此,在函数SomeFuncSample x中,应创建并销毁SomeFunc的局部对象,即样本类型的x,并且main中的样本类型对象s1应保持完整,并且仅在main退出后才应释放。请回答为什么会发生上述行为?为什么会发生上述行为
简短答复:
因为你没有遵守规则
长答覆:
类中有一个指针成员ptr,在构造函数中有动态内存分配,在析构函数中有释放,而代码通过调用复制构造函数(由编译器隐式生成)传递给函数SomeFunc时,会创建对象的临时副本,复制构造函数会创建指针成员的副本。一旦在函数调用结束时销毁临时对象,内存将在析构函数中释放,剩下的指针将悬空。当调用函数PrintVal时,将进一步取消对该无效指针的引用,从而导致未定义的行为,该行为以分段错误的形式表现出来
如何避免这个问题
简短答复:
遵循三的规则
长答覆:
您应该提供一个复制构造函数来创建指针成员ptr的深度副本。这确保在成员中创建的对象的指针成员在程序的整个生命周期内保持有效
编辑:
实际上,问题甚至可能在调用函数之前就出现,特别是在调用以下函数时:
Sample s1= 10;
这将调用转换构造函数
Sample(int i)
要创建一个临时示例对象,然后通过调用隐式复制构造函数用于构造s1对象,如果是这种情况,则创建的临时对象将在创建s1后销毁,使指针成员ptr处于悬空状态
然而,大多数编译器将通过使用复制省略应用优化,从而消除调用复制构造函数的需要&因此这可能不是问题
无论哪种情况,问题的解决方案都是一样的。为什么会发生上述行为
简短答复:
因为你没有遵守规则
长答覆:
类中有一个指针成员ptr,在构造函数中有动态内存分配,在析构函数中有释放,而代码通过调用复制构造函数(由编译器隐式生成)传递给函数SomeFunc时,会创建对象的临时副本,复制构造函数会创建指针成员的副本。一旦在函数调用结束时销毁临时对象,内存将在析构函数中释放,剩下的指针将悬空。当调用函数PrintVal时,将进一步取消对该无效指针的引用,从而导致未定义的行为,该行为以分段错误的形式表现出来
如何避免这个问题
简短答复:
遵循三的规则
长答覆:
您应该提供一个复制构造函数来创建指针成员ptr的深度副本。这确保在成员中创建的对象的指针成员在程序的整个生命周期内保持有效
编辑:
实际上,问题甚至可能在调用函数之前就出现,特别是在调用以下函数时:
Sample s1= 10;
这将调用转换构造函数
Sample(int i)
要创建一个临时示例对象,然后通过调用隐式复制构造函数用于构造s1对象,如果是这种情况,则创建的临时对象将在创建s1后销毁,使指针成员ptr处于悬空状态
然而,大多数编译器将通过使用复制省略应用优化,从而消除调用复制构造函数的需要&因此这可能不是问题
在任何一种情况下,问题的解决方案都是相同的。+1对于提及转换构造函数的编辑,尽管这不是原因,因为RVO@Als:我今天自己创建了我的Stack Exchange帐户,我对答案的质量和快速响应感到惊讶@Abhay:欢迎加入,快乐学习,回头见:+1编辑提及转换构造函数的情况,尽管这不是原因,因为RVO@Als:我今天自己创建了我的Stack Exchange帐户,我对答案的质量和快速响应感到惊讶@阿比海:欢迎加入,快乐学习,再见: