【问题标题】:Why is destructor called in Friend function为什么在Friend函数中调用析构函数
【发布时间】:2020-08-01 08:12:15
【问题描述】:

为什么在这个 Friend 函数中调用析构函数show() C++? 还有,字符指针应该如何初始化,设置为0... main 的完整代码在这里https://justpaste.it/5x7fy

#include<iostream>
using namespace std;
#include<string.h>

class String
{

public:
    char *p;
    int len;
    String()
    {
        cout << "empty constructor" << endl;
        len=0;
        p=0;
    }
    // constructor
    String(const char *s) {
        len=strlen(s);
        p=new char[len+1];
        strcpy(p,s);
    }

    friend String operator+(const String&s, const String&t);
    friend int operator<=(const String&s, const String&t);
    friend void show(const String s);

    ~String() {delete p;}
};

void show(const String s)
{
    cout<<s.p<<endl;
}

编辑,阅读复制构造函数并添加一个:

// copy constructor
String(const String &s)
{
    len=s.len;
    p=new char[len+1]; // s.p;//
    strcpy(p,s.p);
}

之前友元函数参数是传值,变量离开了show函数作用域,所以调用了析构函数,现在是传引用了。

    friend void show(const String & s);
...
    void show(String & s)
    {
        cout<<s.p<<endl;
    }

Edit 更新了空构造函数中字符指针的初始化。

String() {
    p = new char[1]{'\0'};
    len = 1;
};

[最新来源]:https://www.mediafire.com/file/31gb64j7h77x5bn/class38working.cc/file

【问题讨论】:

  • 不是你问的,但你上面的代码和链接的完整代码都没有正确的复制语义。因此,析构函数调用虽然正确,但可能会使您的程序崩溃。
  • 说真的,教师应该在教授 the rule of three 之前停止教授内存泄漏。在大多数情况下忘记删除内存是无害的,无论如何程序都会很快结束,在没有适当的复制构造函数的析构函数中删除是UB。
  • @Yksisarvinen 是的,并且复制构造函数在以这种方式初始化时不起作用。} String string3 = s1+s2

标签: c++ pointers destructor friend


【解决方案1】:

调用析构函数是因为s 是按值传递的。也就是说,当您调用show(something) 时,会将某些内容复制到s 中,然后在show 的执行结束时将其销毁。

【讨论】:

  • 很好的调用就是这样,在函数签名中添加一个 & ,让它通过引用传递,对吗?所以现在它正在运行 show() 函数而不调用析构函数。
  • const String &amp; 是对 const String 的引用;同样String &amp; 是对String 的引用。所以是的,添加它使其通过引用传递。
  • @HugoR 刚刚注意到您的类没有声明复制构造函数(采用单个 const String&amp; 参数)。这意味着编译器会为您生成一个。遗憾的是,它所做的与您想要的不同:它只复制所有字段,因此您最终会得到两个具有相同 p 值的 String 实例。您需要自己实现复制构造函数。
  • 复制构造函数在编辑中,你可以看看。
  • 复制构造函数没问题,假设len == strlen(p)
【解决方案2】:

你的友元函数 show 接受每个值的 String 参数,这意味着无论传递给函数的参数是什么,都会创建一个本地副本并在函数内部使用。当然,这个本地副本会被销毁 - 再次在 show() 函数结束时。

如果您通过引用传递字符串(const string**&** s),您将不会获得额外的临时副本,也不会对其进行任何破坏。

【讨论】:

    猜你喜欢
    • 2021-08-04
    • 2021-04-01
    • 2014-03-05
    • 2018-05-24
    • 2015-08-21
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    相关资源
    最近更新 更多