C++ std:ostringstream和-std=c+的内存错误+;11?
编辑:感谢所有指出问题的人,并在堆栈溢出问题上进行了讨论。我自己投了最后一票 一个相关的问题:CPP既没有提及也没有说明其是临时的。那么多人怎么知道的?或者我是否应该查阅不同的文件C++ std:ostringstream和-std=c+的内存错误+;11?,c++,c++11,memory-leaks,stringstream,temporary-objects,C++,C++11,Memory Leaks,Stringstream,Temporary Objects,编辑:感谢所有指出问题的人,并在堆栈溢出问题上进行了讨论。我自己投了最后一票 一个相关的问题:CPP既没有提及也没有说明其是临时的。那么多人怎么知道的?或者我是否应该查阅不同的文件 我在使用GCC4.7.2的Debian 7.3(x64)下的内存错误方面遇到了很多麻烦,-std=c++11和std::ostringstream。它会导致类似这样的商业结果 完整的程序使用Sqlite。与Valgrind相比,从命令行运行简化案例会打印出两个不同的错误。整个简化案例程序可以在(我认为在这里发布整个
我在使用GCC4.7.2的Debian 7.3(x64)下的内存错误方面遇到了很多麻烦,
-std=c++11
和std::ostringstream
。它会导致类似这样的商业结果
完整的程序使用Sqlite。与Valgrind相比,从命令行运行简化案例会打印出两个不同的错误。整个简化案例程序可以在(我认为在这里发布整个示例有点长)。它所做的只是初始化Sqlite、打开数据库、创建表、关闭数据库并统一数据库。如果发生错误,它会报告错误。没有别的事情发生
下面是简化案例程序的一部分,它只是尝试创建一个表。如果该表存在,则应产生一个错误(确实如此):
在Valgrind下,信息是:
sqlite3_exec failed, error 1
Sqlite error: table
sqlite3_exec failed, error 1
Sqlite error: table test already exists
该程序大量使用了
ostringstream
,Valgrind围绕它们产生了近13个问题,其中9个问题包括底层基本字符串上的运算符删除(void*)
。例如,下面显示了一个(来自t.cpp
的第76行是const char*stmt=qs.str().c_str();
):
==14318==大小为1的无效读取
==14318==at 0x45ACC8:sqlite3\u exec(sqlite3.c:94542)
==14318==0x405D07:main(t.cpp:79)
==14318==地址0x5d89728是大小为127 free'd的块中的24个字节
==14318==0x4C27870处:运算符删除(void*)(vg_replace_malloc.c:502)
==14318==by 0x530EB1F:std::basic_string::~basic_string()(in/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==14318==0x405CF1:main(t.cpp:76)
有人知道这里发生了什么吗?它是ostringstream吗?或者GCC 4.7.2?或者Debian的港口
(对于这个开放式问题,我感到很抱歉。我已经没有事情可做了)。仔细看看这一行:
const char*stmt=qs.str().c_str()代码>
qs.str()。一旦这一行完成执行,指针就不再有效,其他东西可能(也可能)存储在那里
尝试这样做:
std::string strstmt(qs.str());
const char* stmt = strstmt.c_str();
仔细看看这一行:
const char*stmt=qs.str().c_str()代码>
qs.str()。一旦这一行完成执行,指针就不再有效,其他东西可能(也可能)存储在那里
尝试这样做:
std::string strstmt(qs.str());
const char* stmt = strstmt.c_str();
它从qs
中提取一个临时字符串,获取指向其内容的指针,然后销毁临时字符串,使指针悬空。在此之后使用指针将给出未定义的行为
要修复它,您可以将str()
的结果赋给一个变量,这样它就不再是临时的,或者使用此表达式作为sqlite3_exec
的参数,这样临时的结果在该函数调用之后仍然有效。(在第二种情况下,您必须删除第一个断言;但该断言无论如何都是毫无意义的)
它从qs
中提取一个临时字符串,获取指向其内容的指针,然后销毁临时字符串,使指针悬空。在此之后使用指针将给出未定义的行为
要修复它,您可以将str()
的结果赋给一个变量,这样它就不再是临时的,或者使用此表达式作为sqlite3_exec
的参数,这样临时的结果在该函数调用之后仍然有效。(在第二种情况下,您必须删除第一个断言;但该断言无论如何都是毫无意义的)。const char*stmt=qs.str().cstr()代码>坏。@Simple让我们看看谁是第一个找到重复项的;)我知道这不是答案,但是str()
返回一个缓冲区副本,这样做str()。reserve(x)
是徒劳的。是的,我想知道这是什么:str()。reserve(x)
doing@noloader是的。请注意,返回类型是string
而不是string&
。明确提到了这个可能的错误。const char*stmt=qs.str().c_str()代码>坏。@Simple让我们看看谁是第一个找到重复项的;)我知道这不是答案,但是str()
返回一个缓冲区副本,这样做str()。reserve(x)
是徒劳的。是的,我想知道这是什么:str()。reserve(x)
doing@noloader是的。请注意,返回类型是string
而不是string&
。明确提到了这个可能的错误。谢谢迈克。现在我知道发生了什么,我就能解决问题了。相关报道:人们是如何知道这是暂时的(他们是在过去被烧死的,还是只是常识)?我使用的两个引用没有说明这是一个临时对象。是C++标准规定的行为吗?@诺洛德:我不能为人们说话,但我通过这样被烧毁来了解暂时性的东西。它的指定行为是:str()
按值返回字符串;返回值是临时的;临时变量在创建它们的完整表达式的末尾被销毁(这里不适用一个例外)。谢谢Mike。现在我知道发生了什么,我就能解决问题了。相关报道:人们是如何知道这是暂时的(他们是在过去被烧死的,还是只是常识)?我使用的两个引用没有说明这是一个临时对象。这种行为是特定的吗
std::string strstmt(qs.str());
const char* stmt = strstmt.c_str();
const char* stmt = qs.str().c_str();