我有一个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 ++处理内存分配。
答案 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
的某些部分在运行时库中实现(并非不可能),则这些定义不会对那里的预编译代码产生任何影响。然后检测只会是部分检测并错过一些分配或解除分配。