对象按值传递时调用的析构函数

Sha*_*uri 10 c++

即使通过普通的按值调用参数传递机制将对象传递给函数,理论上它们可以保护和隔离调用参数,但是仍然可能发生可能影响甚至损坏的副作用,用作参数的对象.例如,如果用作参数的对象分配内存并在销毁时释放该内存,那么在调用析构函数时,函数内部的本地副本将释放相同的内存.这将使原始物体损坏并且实际上无用.

这是用C++编写的:完整参考

在这个程序在这里

#include<iostream>

using namespace std;

class Sample
{         
 public:
         int *ptr;
         Sample(int i)
         {
         ptr = new int(i);
         }
         ~Sample()
         {
         cout<<"destroyed";
         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();
}
Run Code Online (Sandbox Code Playgroud)

它会在对象s1从对象返回时被销毁时生成运行时错误.我无法弄清楚为什么会发生这种情况,因为应该制作副本.我想也许是因为班级定义中没有复制构造函数.但我很惊讶地发现,如果使用这个函数声明

 void SomeFunc(Sample &x)
{
 cout << "Say i am in someFunc " << endl;
}
Run Code Online (Sandbox Code Playgroud)

在此声明中不会发生错误.不应该在这里发生错误,因为它被引用了吗?谁能解释两种情况都会发生什么.

JBL*_*JBL 11

这确实是因为您没有提供复制构造函数.因此,编译器将为您生成一个,这将执行简单的复制.这就是指针的微不足道的副本,这里有问题.

对于以下声明

void SomeFunc(Sample x);
Run Code Online (Sandbox Code Playgroud)

传递s1给函数时确实会有一个副本,但是这个副本将有一个指针的副本,也就是说,两个对象将指向相同的副本int.

然后,当退出该函数时,副本将被销毁并将删除该指针,将原始对象留在调用代码中,并且指针刚刚删除(记住,它们指向同一个东西).

然后,为以下声明

void SomeFunc(Sample &x);
Run Code Online (Sandbox Code Playgroud)

你没有任何副本,因此问题没有出现.实际上,通过引用传递意味着在函数内部,Sample您正在操作的对象与传递给函数的对象完全相同,并且在函数退出时不会被销毁.