std:ostringstream和-std = c ++ 11的内存错误?

jww*_*jww 1 c++ memory-leaks stringstream temporary-objects c++11

编辑:感谢所有指出问题的人,并在Stack Overflow上进行了讨论.我自己投了最后一次投票.

一个相关的问题:在没有CPP参考ostringstreamostringstream::str说明其暂时的.这么多人怎么知道的?或者我应该咨询不同的文件?


我有很多与在Debian 7.3(x64)的内存错误麻烦GCC 4.7.2,-std=c++11std::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.cppconst 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的端口?

(对于开放式的问题,我很抱歉.我已经没有事情可做了).

Mik*_*our 6

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)