关于c ++:String.replace()和动态内存

String.replace() and dynamic memory

我知道Arduino的string.replace函数使用realloc()。

我的"replacement"函数构建了一个char缓冲区,然后将其分配给输入字符串,在动态内存分配方面是否更好?

我知道我不应该一开始就用绳子,但我暂时还坚持着。

这是我的职责:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void replaceSubstr(String& in, String subin, String subout){

    int s = in.indexOf(subin);

     if(s > -1)
    {
     int a = in.length();
     int b = subout.length();
     int c = subin.length();
     int len = (a + (b - c))+1;

    char buff[len];  
    memcpy(buff, in.c_str(), s);
    memcpy(&buff[s], subout.c_str(), b);
    memcpy(&buff[s+b], in.substring(s+c).c_str(), a-(s+c));

     buff[len-1] = '\0';
     in = buff;
    }
}


根据消息来源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
String::String(const char *cstr)
{
    init();
    if (cstr) copy(cstr, strlen(cstr));
}
...
inline void String::init(void)
{
    buffer = NULL;
    capacity = 0;
    len = 0;
}
...
String & String::copy(const char *cstr, unsigned int length)
{
    if (!reserve(length)) {
        invalidate();
        return *this;
    }
    len = length;
    strcpy(buffer, cstr);
    return *this;
}
...
void String::invalidate(void)
{
    if (buffer) free(buffer);
    buffer = NULL;
    capacity = len = 0;
}
...
unsigned char String::reserve(unsigned int size)
{
    if (buffer && capacity >= size) return 1;
    if (changeBuffer(size)) {
        if (len == 0) buffer[0] = 0;
        return 1;
    }
    return 0;
}

你的一行作业

1
 in = buff;

也进行所有分配。

必须这样做,原来的String不能在不同的内存模型中保存buffer,只有一个"动态分配"有意义。

从广泛的角度来看,现实生活中的许多C内存模型(堆栈、静态、由new分配、由calloc分配,如果它们不同)都必须减少,混合是危险的。例如,堆栈变量不能寿命更长-必须复制到"allocated"。

您检查了新的可能性,这很好,但我同意Aconcagua在实现方面的信任,而不是替换原始的内存模型。

资料来源:https://github.com/arduino/arduino/blob/master/hardware/arduino/avr/cores/arduino/wstring.cpp

编辑:同意const参数等…


从效率的角度来看,可以将subin和subout作为const引用(String const& /*...*/)传递,这样可以避免复制这两个字符串。

在C++中不支持EDOCX1 1,仅在C(从C99上),参见这里。除非编译器支持堆栈上的动态数组作为扩展名,否则必须在堆上分配数组(new char[len])。

然后,您可以尝试重用in字符串的缓冲区,但是,只有当替换字符串不长于要替换的字符串时(更准确地说,较长的部分必须与字符串缓冲区相匹配,该缓冲区内部分配用于保存内容,并且可能长于后者),这才有效。在插入替换之前,您必须在要替换的部分之后移动字符串的部分(例如,使用memmove)。

然而,所有这些都需要处理字符串类的内部(包括调整内容的大小和可能的容量,如果由于太短而不得不重新分配自己的缓冲区),那么在没有脏的黑客的情况下,您无法访问这些黑客,这些黑客会在字符串类更改后立即中断……

我的建议:相信Arduino的实现——你应该假设它已经实现了你正在尝试的:如果内部缓冲区足够长,能够容纳整个结果,那么它将被使用(不需要在索引0-S中移动或复制字符串,将部分从S+C适当地移动到末尾,然后在子输出的内容中复制)一个d只有在内部缓冲区不够长时才使用重新分配。