字符串分配内存
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", "");
,除非您要求,否则不会分配新字符串。
所以它比你想象的要微妙得多!
在 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", "");
,除非您要求,否则不会分配新字符串。
所以它比你想象的要微妙得多!