jww*_*jww 1 c++ memory-leaks stringstream temporary-objects c++11
编辑:感谢所有指出问题的人,并在Stack Overflow上进行了讨论.我自己投了最后一次投票.
一个相关的问题:在没有CPP参考ostringstream
或ostringstream::str
说明其暂时的.这么多人怎么知道的?或者我应该咨询不同的文件?
我有很多与在Debian 7.3(x64)的内存错误麻烦GCC 4.7.2,-std=c++11
和std::ostringstream
.它导致bizaare结果,如/sf/ask/1488257081/.
完整的程序使用Sqlite.从命令行运行简化案例与Valgrind打印2个不同的错误.整个简化案例程序可以在Code Viewer中找到(我认为在这里发布整个示例有点长).它所做的只是初始化Sqlite,打开数据库,创建表,关闭数据库,以及将数据库统一化.如果发生错误,它会报告错误.没有其他事情发生.
这是简化案例程序的一部分,它只是试图创建一个表.如果表存在,它应该产生错误(它会):
ostringstream qs;
qs.str().reserve(96);
qs << "CREATE TABLE test";
qs << "(";
qs << " userid INTEGER PRIMARY KEY AUTOINCREMENT,";
qs << " username TEXT,";
qs << " salt BLOB,";
qs << " hmac BLOB";
qs << ");";
const char* stmt = qs.str().c_str();
AC_ASSERT(NULL != stmt);
rc = sqlite3_exec(db, stmt, NULL, NULL, &err);
AC_ASSERT(rc == SQLITE_OK);
if(rc != SQLITE_OK)
{
ostringstream oss;
oss.str().reserve(96);
oss << "sqlite3_exec failed, error " << rc;
LogError(oss.str().c_str());
oss.clear(), oss.str("");
oss << "Sqlite error: " << err;
LogError(oss.str().c_str());
// Break, handle error
}
Run Code Online (Sandbox Code Playgroud)
但是,在命令行下,消息是:
sqlite3_exec failed, error 1
Sqlite error: table
Run Code Online (Sandbox Code Playgroud)
在Valgrind下,消息是:
sqlite3_exec failed, error 1
Sqlite error: table test already exists
Run Code Online (Sandbox Code Playgroud)
该计划大量使用ostringstream
,Valgrind以其为中心产生了近13个问题,其中9个问题包括operator delete(void*)
基础问题basic_string
.例如,一种如下所示(并从管线76 t.cpp
是const char* stmt = qs.str().c_str();
):
==14318== Invalid read of size 1
==14318== at 0x45ACC8: sqlite3_exec (sqlite3.c:94542)
==14318== by 0x405D07: main (t.cpp:79)
==14318== Address 0x5d89728 is 24 bytes inside a block of size 127 free'd
==14318== at 0x4C27870: operator delete(void*) (vg_replace_malloc.c:502)
==14318== by 0x530EB1F: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==14318== by 0x405CF1: main (t.cpp:76)
Run Code Online (Sandbox Code Playgroud)
有没有人对这里发生了什么有任何想法?是ostringstream
吗?或许GCC 4.7.2?或者也许是Debian的端口?
(对于开放式的问题,我很抱歉.我已经没有事情可做了).
const char* stmt = qs.str().c_str();
Run Code Online (Sandbox Code Playgroud)
从中提取一个临时字符串qs
,获取指向其内容的指针,然后销毁临时指针悬空指针.在此之后使用指针将给出未定义的行为.
要修复它,您可以将结果str()
赋给变量,使其不再是临时的,或者使用此表达式作为参数sqlite3_exec
,以便临时存活直到该函数调用之后.(在第二种情况下,你必须删除第一个断言;但这个断言无论如何都是毫无意义的).
小智 5
仔细看看这一行:
const char* stmt = qs.str().c_str();
qs.str()
为您提供一个临时std::string
对象,从中可以获取指向内部char*
数组的指针.一旦该行完成其执行,您的指针就不再有效,并且其他东西可能(并且可能)存储在那里.
尝试这样做:
std::string strstmt(qs.str());
const char* stmt = strstmt.c_str();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3351 次 |
最近记录: |