在 D 中创建字符串而不分配内存?

发布于 2024-12-07 06:51:56 字数 700 浏览 6 评论 0原文

是否有任何类型安全的方法可以在 D 中创建字符串,使用仅在运行时可用的信息,而不分配内存?

我可能想要做的一个简单的例子:

void renderText(string text) { ... }

void renderScore(int score)
{
    char[16] text;
    int n = sprintf(text.ptr, "Score: %d", score);
    renderText(text[0..n]); // ERROR
}

使用这个,你会得到一个错误,因为 text 的切片不是不可变的,因此不是 string (即 immutable(char)[])

我只能想到三种方法来解决这个问题:

  1. 将切片转换为 string。它有效,但很丑。
  2. 使用切片分配一个新字符串。这可行,但我不想分配内存。
  3. 更改 renderText 以采用 const(char)[]。这在这里可行,但是(a)它很难看,(b)Phobos 中的许多函数都需要 string,所以如果我想以相同的方式使用它们,那么这是行不通的。

这些都不是特别好。我错过了什么吗?其他人如何解决这个问题?

Is there any typesafe way to create a string in D, using information only available at runtime, without allocating memory?

A simple example of what I might want to do:

void renderText(string text) { ... }

void renderScore(int score)
{
    char[16] text;
    int n = sprintf(text.ptr, "Score: %d", score);
    renderText(text[0..n]); // ERROR
}

Using this, you'd get an error because the slice of text is not immutable, and is therefore not a string (i.e. immutable(char)[])

I can only think of three ways around this:

  1. Cast the slice to a string. It works, but is ugly.
  2. Allocate a new string using the slice. This works, but I'd rather not have to allocate memory.
  3. Change renderText to take a const(char)[]. This works here, but (a) it's ugly, and (b) many functions in Phobos require string, so if I want to use those in the same manner then this doesn't work.

None of these are particularly nice. Am I missing something? How does everyone else get around this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我爱人 2024-12-14 06:51:56

您有 char 的静态数组。您希望将其传递给采用 immutable(char)[] 的函数。在没有任何分配的情况下实现这一点的唯一方法是强制转换。想一想。你想要的是一种类型表现得像另一种类型。这就是选角的作用。您可以选择使用 assumeUnique 来执行此操作,因为这正是您正在寻找的转换,但是这是否真正为您带来任何好处是值得商榷的。它的主要目的是记录您通过强制转换所做的事情是使被强制转换的值被视为不可变,并且没有其他引用它。看看你的例子,这基本上是正确的,因为它是函数中的最后一件事,但你是否想这样做通常取决于你。鉴于它是一个静态数组,如果搞砸了并将其传递给允许对其引用泄漏的函数,则会面临内存问题的风险,我不确定 assumeUnique 是最佳选择。但话又说回来,这取决于你。

无论如何,如果您要进行强制转换(无论是显式强制转换还是使用 assumeUnique),您需要确保将其传递给的函数不会泄漏对以下数据的引用:你正在传递给它。如果是这样,那么你就是在自找麻烦。

当然,另一个解决方案是更改函数,使其采用 const(char)[],但这仍然存在泄漏对传入数据的引用的风险。因此,您仍然需要确定该函数实际上要做什么。如果它是pure,则不会返回const(char)[](或任何可能包含const(char)[]),并且它不可能泄漏该函数的任何其他参数,那么你就安全了,但如果其中任何一个不正确,那么你就必须小心了。因此,最终,我相信使用 const(char)[] 而不是转换为 string 真正能给你带来的是你不必进行转换。这仍然更好,因为它避免了搞砸强制转换的风险(并且一般来说,尽可能避免强制转换会更好),但在转义引用方面您仍然需要担心所有相同的事情。

当然,这还要求您能够更改函数以具有您想要的签名。如果你做不到这一点,那么你就必须进行投射。我相信此时,Phobos 的大多数基于字符串的函数都已更改,以便它们在字符串类型上进行模板化。因此,对于火卫一来说,现在的问题应该比以前少一些。某些函数(特别是 std.file 中的函数)仍然需要模板化,但最终,Phobos 中专门需要 string 的函数应该相当罕见,并且有充分的理由需要它。

然而,最终的问题是,您试图将静态数组视为动态数组,虽然 D 绝对允许您这样做,但这样做确实会带来一定的风险,并且您需要确定您正在使用的函数不会泄漏对您传递给它们的本地数据的任何引用。

You have static array of char. You want to pass it to a function that takes immutable(char)[]. The only way to do that without any allocation is to cast. Think about it. What you want is one type to act like it's another. That's what casting does. You could choose to use assumeUnique to do it, since that does exactly the cast that you're looking for, but whether that really gains you anything is debatable. Its main purpose is to document that what you're doing by the cast is to make the value being cast be treated as immutable and that there are no other references to it. Looking at your example, that's essentially true, since it's the last thing in the function, but whether you want to do that in general is up to you. Given that it's a static array which risks memory problems if you screw up and you pass it to a function that allows a reference to it to leak, I'm not sure that assumeUnique is the best choice. But again, it's up to you.

Regardless, if you're doing a cast (be it explicitly or with assumeUnique), you need to be certain that the function that you're passing it to is not going to leak references to the data that you're passing to it. If it does, then you're asking for trouble.

The other solution, of course, is to change the function so that it takes const(char)[], but that still runs the risk of leaking references to the data that you're passing in. So, you still need to be certain of what the function is actually going to do. If it's pure, doesn't return const(char)[] (or anything that could contain a const(char)[]), and there's no way that it could leak through any of the function's other arguments, then you're safe, but if any of those aren't true, then you're going to have to be careful. So, ultimately, I believe that all that using const(char)[] instead of casting to string really buys you is that you don't have to cast. That's still better, since it avoids the risk of screwing up the cast (and it's just better in general to avoid casting when you can), but you still have all of the same things to worry about with regards to escaping references.

Of course, that also requires that you be able to change the function to have the signature that you want. If you can't do that, then you're going to have to cast. I believe that at this point, most of Phobos' string-based functions have been changed so that they're templated on the string type. So, this should be less of a problem now with Phobos than it used to be. Some functions (in particular, those in std.file), still need to be templatized, but ultimately, functions in Phobos that require string specifically should be fairly rare and will have a good reason for requiring it.

Ultimately however, the problem is that you're trying to treat a static array as if it were a dynamic array, and while D definitely lets you do that, you're taking a definite risk in doing so, and you need to be certain that the functions that you're using don't leak any references to the local data that you're passing to them.

提赋 2024-12-14 06:51:56

从 std 查看 assumeUnique .exception 乔纳森的回答。

Check out assumeUnique from std.exception Jonathan's answer.

空心空情空意 2024-12-14 06:51:56

不可以,您不能创建没有分配的字符串。您的意思是访问吗?为了避免分配,您必须使用切片或指针来访问先前创建的字符串。但不确定强制转换,它可能会也可能不会为新字符串分配新的内存空间。

No, you cannot create a string without allocation. Did you mean access? To avoid allocation, you have to either use slice or pointer to access a previously created string. Not sure about cast though, it may or may not allocate new memory space for the new string.

小猫一只 2024-12-14 06:51:56

解决这个问题的一种方法是将可变字符复制到新的不可变版本中,然后对其进行切片:

void renderScore(int score)
{
    char[16] text;
    int n = sprintf(text.ptr, "Score: %d", score);
    immutable(char)[16] itext = text;
    renderText(itext[0..n]);
}

但是:

  1. 由于错误,DMD 目前不允许这样做。
  2. 您正在创建不必要的副本(比 GC 分配更好,但仍然不是很好)。

One way to get around this would be to copy the mutable chars into a new immutable version then slice that:

void renderScore(int score)
{
    char[16] text;
    int n = sprintf(text.ptr, "Score: %d", score);
    immutable(char)[16] itext = text;
    renderText(itext[0..n]);
}

However:

  1. DMD currently doesn't allow this due to a bug.
  2. You're creating an unnecessary copy (better than a GC allocation, but still not great).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文