C ++字符串扩展会导致分配错误

时间:2017-11-25 15:43:15

标签: c++ string memory memory-management memory-leaks

我有一个memory leaking library来检查我的应用程序是否有内存泄漏。但是,一个非常简单的程序已经导致内存泄漏。

考虑以下程序将14个字符分配给字符串Message:

string Message;
int main() {
    Message = "This is a test";
    }

导致无内存错误。

但是,当我尝试初始化长度超过15个字符的字符串Message(假设为20)时,它会给我一个内存泄漏错误:

string Message;
int main() {
    Message = "This is a test which";
    }

导致错误:

Leaks found: 1 allocations (31 bytes)

如果你初始化一个字符串(最多15个字符+ \ 0),c ++正在分配16个字节的空间:

string Message;

但是,如果我将消息初始化为:

string Message = "This is a test which is long enough to hold 'This is a test which'";

之前的内存泄漏错误消失了。

因此,当我尝试使用溢出字符串缓冲区实际声明大小的动态字符串大小时,C ++不能很好地分配内存吗?

要想象:

string Message; //Allocates 16 bytes of memory whereof the 16th position is \0
Message = "This is a test which"; //longer then 15 --> Memory Leak

但是,如果我执行以下操作,则不会产生任何错误:

string Message = "This is a test which can hold a long string";
Message = "This is a test which"; //NO ERRORS

如何在C ++中克服这个问题?我更喜欢坚持使用字符串,但我需要知道如何正确扩展字符串。因此,如果字符串内容溢出先前分配的内存,让C ++处理内存分配。

2 个答案:

答案 0 :(得分:3)

消息是一个全局变量。

在构建全局变量之后,但在启动main之前,您的检漏仪必须拍摄内存状态的快照。

然后在主要结束后查看内存,但在全局变量被破坏之前。

std :: string经常(但不总是 - 依赖于实现)对短字符串有一个实现优化...但是在堆上分配了比这更长的字符串。

你的泄漏检测器正在看到堆上的字符串,没有意识到消息析构函数将很快被调用,会在短时间内将其释放回堆中。

答案 1 :(得分:2)

set.seed(24) v1 <- factor(sample(-2:3, 20, replace = TRUE)) levels(v1) <- setNames(rep(c('safe', 'mild risky', 'risky'), each = 2), -2:3)[levels(v1)] 标头尝试通过添加一组leaker.h来拦截内存分配:

#defines

如果我们忘记重新定义明确不允许的/* preprocessor magic to override built-in allocation functions with our own */ #define malloc(size) _malloc(size, __FILE__, __func__, __LINE__) #define calloc(n, size) _calloc(n, size, __FILE__, __func__, __LINE__) #define free(ptr) _free(ptr, __FILE__, __func__, __LINE__) #define realloc(ptr, size) _realloc(ptr, size, __func__, __FILE__, __LINE__) #ifdef __cplusplus /* hackish solution to the problem of overriding C++ operator new/delete */ extern const char *_leaker_file; extern const char *_leaker_func; extern unsigned long _leaker_line; #define new (_leaker_file=__FILE__, _leaker_func=__func__, \ _leaker_line=__LINE__) && 0 ? NULL : new #define delete _leaker_file=__FILE__, _leaker_func=__func__, \ _leaker_line=__LINE__, delete new等关键字,那么只有delete实现的每个部分都定义为内联函数时,此黑客才有机会工作。

如果std::string的某些部分在运行时库中实现(并非不可能),则这些定义不会对那里的预编译代码产生任何影响。然后检测只会是部分检测并错过一些分配或解除分配。