字符串分配内存

Allocation memory for string

在 D 中,字符串是不可变 char[] 的别名。所以每一个字符串处理操作都会分配内存。我想检查一下,但在替换字符串中的符号后,我看到了相同的地址。

string str = "big";
writeln(&str);
str.replace("i","a");
writeln(&str);

输出:

> app.exe
19FE10
19FE10

我试过使用 ptr:

string str = "big";
writeln(str.ptr);
str.replace(`i`,`a`);
writeln(str.ptr);

得到下一个输出:

42E080
42E080

所以它显示的是同一个地址。为什么?

在 D 中,所有数组都是长度 + 指向数组值开头的指针。这些通常存储在恰好是 RAM 的堆栈中。

当你获取一个变量的地址(在函数体中)时,你真正做的是获取一个指向堆栈的指针。

要获取数组值的地址,请使用 .ptr。 因此,将 &str 替换为 str.ptr,您将获得正确的输出。

您在代码中犯了一个简单的错误:

str.replace("i","a");

str.replace returns 完成替换的新字符串,它实际上并没有替换现有变量。所以尝试 str = str.replace("i", "a"); 看看变化。

但是你也对分配做了一个过于笼统的陈述:

So every operation on string processing with allocation of memory.

错了,很多操作不需要分配新内存。任何可以分割现有字符串的东西都可以这样做,避免需要新的内存:

import std.string;
import std.stdio;

void main() {
        string a = "  foo  ";
        string b = a.strip();
        assert(b == "foo"); // whitespace stripped off...

        writeln(a.ptr);
        writeln(b.ptr); // but notice how close those ptrs are
        assert(b.ptr == a.ptr + 2); //  yes, b is a slice of a
}

replace 也将 return 原始字符串,如果实际上没有进行替换的话:

string a = "  foo  ";
string b = a.replace("p", "a"); // there is no p to replace
assert(a.ptr is b.ptr); // so same string returned

索引和迭代不需要新的分配(当然)。信不信由你,但即使追加有时也不会分配,因为切片末尾可能还有未使用的内存(尽管通常会使用)。

还有各种 return 范围对象的函数,这些函数会在您遍历它们时进行更改,从而避免分配。例如,您可以执行 filter!(ch => ch != 'f')(a); 之类的操作并循环遍历,而不是 replace(a, "f", "");,除非您要求,否则不会分配新字符串。

所以它比你想象的要微妙得多!