String.replace() 和动态内存

String.replace() and dynamic memory

本文关键字:动态 内存 replace String      更新时间:2023-10-16

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

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

我知道我不应该首先使用 String,但我暂时坚持使用它。

这是我的函数:

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] = '';
     in = buff; 
    }
}

按来源

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;
}

您的单行分配

 in = buff; 

也进行所有分配。

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

从广义上讲,许多C内存模型(堆栈,静态,由new分配,如果它们不同,则由calloc分配(必须在现实生活中减少 - 混合是危险的。例如,堆栈变量不能存活更长时间 - 必须复制到"已分配"。

你检查新的可能性,这很好,但我同意Aconcagua对实现的信任,而不是取代原始的内存模型。

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

编辑:同意const论点等...

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

char buff[len]在C++中不受支持,仅在 C 中受支持(从 C99 开始(,请参阅此处。您必须在堆上分配数组(new char[len](——除非您的编译器支持堆栈上的动态数组作为扩展。

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

然而,所有这些都需要处理 String 类的内部(包括例如调整内容的大小和可能的容量,如果您由于太短而不得不重新分配缓冲区(,如果没有肮脏的黑客,您将无法访问,一旦 String 类更改就会中断......

我的建议:相信 arduino 的实现 - 你应该假设它已经完成了你正在尝试的事情:如果内部缓冲区足够长以保存整个结果,它将被使用(不需要移动或复制索引 0-s 中的字符串,适当地将部分从 s+c 移动到末尾,然后复制 subout 的内容(并且使用 repositionate, 如果内部缓冲区不够长