malloc - D语言中使用malloc的问题:为什么writeln在这个例子中调用了两次析构函数
问题描述
我正在尝试为使用标准 C malloc 函数存储其数据的 C 库 (libmpdec) 编写 D 包装器。但是我的程序中有一些令人讨厌的错误,我不知道如何解决。所以我写了下面的测试例子,试图理解这一点。这个想法是创建一个结构,该结构包含一个指向在构造函数中使用 malloc 分配的内存区域的指针,其中包含一个以零结尾的 C 字符串,并使用析构函数释放该区域。我也可以使用 printf 打印字符串。当我尝试实现一个 toString() 方法以便可以使用标准 D 函数 writeln 时,问题就出现了。由于某种我不明白的原因,析构函数似乎被调用了两次!(在 writeln 之后),因此会发生分段错误。
import std.stdio;
import core.stdc.stdlib;
import std.string;
import core.stdc.string;
struct Prueba {
char* pointer;
string name;
this(string given_name)
{
writeln("calling the constructor");
pointer= cast (char*) malloc(char.sizeof*10);
name=given_name;
char* p= pointer;
*p= 'a';
p++;
*p= 'b';
p++;
*p= '\n';
p++;
*p= '\0';
}
~this()
{
writeln("\n calling the destructor");
free(pointer);
}
void print()
{
printf("Using printf %s \n",pointer);
}
string toString()
{
ulong len=strlen(pointer);
return cast(string) pointer[0..len];
}
}
void main()
{
writeln("version 1");
Prueba p=Prueba("a");
writeln("using writeln ",p);
p.print();
}
但是,如果我将结果存储在一个字符串变量中,例如
string s=p.toString();
writeln("using writeln ",s);
该程序只是工作!我不知道为什么!
您可以在以下位置查看我的测试程序的两个版本
https://github.com/pdenapo/example_programs_in_D/tree/master/using_malloc
非常感谢您的帮助!
更新:似乎 writeln 在这里没有任何作用。我可以用类似的东西得到同样的结果
void probando(Prueba q)
{
q.print();
}
probando(p);
问题似乎是在调用函数时创建了 p 的副本。
解决方案
在这种情况下,最好查看是否是同一个实例被销毁。添加&this
到writeln
调用中,我得到以下输出:
version 1
calling the constructor at 6FBB70F960
Instance on stack: 6FBB70F960
using writeln ab
calling the destructor at 6FBB70F820
calling the destructor at 6FBB70F7F0
正如我们所看到的,指针是不同的,所以有两个实例。
D 结构是值类型,因此被复制和移动。当您调用带有类参数的函数时,实际上传递的是指针,它基本上表示“您要查找的类实例在那边”。使用结构创建一个副本,突然之间,您有两个独立的对象过着各自独立的生活。
当然,这不是您想要的 - Prueba 实际上不是可复制类型,因为拥有两个副本将导致对析构函数的两次调用,从而导致双重释放。要将其标记为不可复制,只需添加@disable this(this);
以禁用postblit,编译器将在创建副本时向您抛出错误消息。
这将导致writeln
在线编译器错误,您将不得不手动调用toString
,例如:writeln("using writeln ", p.toString());
请注意,不可复制的结构可以传递给函数 asref
,因为这不会创建新副本。我们无法真正修改writeln
来做到这一点,但对于您自己的功能来说,这是值得了解的。
推荐阅读
- javascript - 简单的 Javascript:在数组上运行函数
- c# - 为什么我的应用程序随着时间的推移变得反应迟钝?
- javascript - 如何在 refFromURL() 中插入数组中的链接 - 存储 firebase
- c - 试图理解c中的死锁
- sql - 选择语句无法找到拼写错误的参数名称
- python - 从多列中过滤数据
- prolog - Prolog中事实和谓词的程序性和声明性阅读
- php - 在 WHM/cPanel 中禁用 output_buffering
- javascript - 如何在 NodeJs 中发回响应之前等待循环完成运行?
- c# - EF 不断抛出错误 System.InvalidOperationException ASP.NET MVC