std:ostringstream和-std = c ++ 11出现内存错误? [英] Memory Error with std:ostringstream and -std=c++11?

查看:436
本文介绍了std:ostringstream和-std = c ++ 11出现内存错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:感谢所有指出问题的人,并且在堆栈溢出中进行了讨论.我本人最后一次投票结束.

EDIT: Thanks to everyone who pointed out the problem, and that it was discussed on Stack Overflow. I cast the last close vote myself.

一个相关问题: ostringstream ostringstream::str 声明其为临时文件.这么多人怎么知道?还是我应该查阅其他文档?

A related question: neither CPP Reference on ostringstream or ostringstream::str state its a temporary. How did so many people know? Or is there different documentation I should have consulted?

在GCC 4.7.2,-std=c++11std::ostringstream的Debian 7.3(x64)下,我在内存错误方面遇到很多麻烦.它会导致结果混乱,例如 https://stackoverflow.com/questions/21260815/哪个在此创建表错误消息中.

I'm having a lot of trouble with memory errors under Debian 7.3 (x64) with GCC 4.7.2, -std=c++11 and std::ostringstream. Its leading to bizaare results like https://stackoverflow.com/questions/21260815/which-r-in-this-create-table-error-message.

完整的程序使用Sqlite.与Valgrind相比,从命令行运行精简版会显示2种不同的错误.整个简化案例程序可在代码查看器中找到(我认为发布该代码很久了整个示例在这里).它所做的只是初始化Sqlite,打开数据库,创建表,关闭数据库并统一数据库.并且它会报告错误(如果发生).什么也没有发生.

The full blown program uses Sqlite. Running a reduced case from the command line vs. Valgrind prints 2 different errors. The entire reduced case program is available at Code Viewer (I thought it was kind of long to post the entire sample here). All it does is initializes Sqlite, opens a database, creates a table, closes the database, and unitializes the database. And it reports errors if they occur. There's nothing else occurring.

这是简化案例程序的一部分,该程序只是尝试创建表.如果该表存在,它将产生一个错误(确实如此):

Here's part of the reduced case program that simply tries to create a table. If the table exists, it should produce an error (which it does):

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
}

但是,在命令行下,消息是:

However, under command line, the message is:

sqlite3_exec failed, error 1
Sqlite error: table 

在Valgrind之下,消息是:

Under Valgrind, the message is:

sqlite3_exec failed, error 1
Sqlite error: table test already exists

该程序大量使用了ostringstream,Valgrind围绕它们生成了近13个问题,其中9个问题包含在基础basic_string上的operator delete(void*).例如,下面显示了一个(t.cpp中的第76行是const char* stmt = qs.str().c_str();):

The program makes heavy use of ostringstream, and Valgrind produces nearly 13 issues centered around them, 9 of which include operator delete(void*) on the underlying basic_string. For example, one is shown below (and line 76 from t.cpp is 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)

有人对这里发生的事情有任何想法吗?是ostringstream吗?还是GCC 4.7.2?或者也许是Debian的港口?

Does anyone have any ideas of what's going on here? Is it ostringstream? Or perhaps GCC 4.7.2? Or maybe Debian's port?

(对于开放式问题,我们深表歉意.我没事做.)

(And sorry for the open ended question. I've run out of things to do).

推荐答案

const char* stmt = qs.str().c_str();

qs中提取一个临时字符串,获取指向其内容的指针,然后销毁该临时字符串,使该指针悬空.在此之后使用指针将产生不确定的行为.

That extracts a temporary string from qs, takes a pointer to its content, then destroys the temporary leaving the pointer dangling. Using the pointer after this will give undefined behaviour.

要修复此问题,您可以将str()的结果分配给一个变量,使其不再是临时的,或者将该表达式用作sqlite3_exec的参数,以便该临时项可以保留到该函数调用之后. (在第二种情况下,您必须删除第一个断言;但是该断言反而是毫无意义的.)

To fix it, you could either assign the result of str() to a variable, so that it's no longer temporary, or use this expression as the argument to sqlite3_exec, so that the temporary survives until after that function call. (In the second case, you'd have to remove the first assertion; but that assertion is rather pointless anyway).

这篇关于std:ostringstream和-std = c ++ 11出现内存错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆