为什么在推入向量后内存被破坏了。在下面的程序中,我有一个带字符串var的结构(它不是指针)。我每次创建一个本地struct对象并分配一个字符串值并推送到向量。在推送到向量后,我正在对本地struct对象进行更改。但是这种变化正在向量结构对象的字符串数据中反映出来。
#include <iostream>
#include <vector>
#include <string>
#include <memory.h>
using namespace std;
void PushVector(string);
struct thread_info
{
int id;
string threadname;
bool bval;
};
std::vector<thread_info> myvector;
int main ()
{
PushVector("Thread1"); // valid data into vector
PushVector("Thread2");
struct thread_info print;
while(!myvector.empty())
{
for(unsigned int index = 0; index < myvector.size(); ++index )
{
print = myvector.at(index);
cout<<"id : "<<print.id<<"\nthread name : "<<print.threadname<<"\nbool value : "<<print.bval<<endl;
}
myvector.clear();
}
return 0;
}
void PushVector(const string str)
{
std::cout << "Push the thread name to vector\n";
struct thread_info thread;
thread.id = 10;
thread.threadname = str;
thread.bval = true;
myvector.push_back (thread); //copying struct obj to vector
char* p = (char* )thread.threadname.c_str();
memcpy(p,"Wrong", 5); //==> Memory corrupting with invalid data after push back. Is it a limitation in C++?
thread.threadname = "blabla"; //trying to corrupt directly to string object
}
O / P: 将线程名称推送到矢量
将线程名称推送到矢量
id:10
线程名称:Wrongd1 ==&gt;内存已损坏?为什么没有blabla字符串?
bool值:1
id:10
线程名称:Wrongd2 ==&gt;内存已损坏?为什么没有blabla字符串?
bool值:1
答案 0 :(得分:5)
memcpy
.c_str()
的结果是错误。事实上你必须用一个演员而不是暗示来攻击const
吗?哪种学习资源教会你这样做?
正如paulm所说:
像这样踩到弦乐的记忆只会导致眼泪。
std::string::c_str()
返回一个指向您不应修改的常量缓冲区的指针;由于某些工具链中存在某些优化(例如GCC中的SSO&lt; 5.0),它甚至可能不是真正的底层缓冲区,这对你来说就好了。
忘记memcpy
;这不是C。
best ,您可以这样做:
thread.threadname.resize(5);
memcpy(&thread.threadname[0], "Wrong", 5);
或者,在C ++代码中:
thread.threadname.resize(5);
std::copy("Wrong", "Wrong"+5, &thread.threadname[0]);
但是,对于实际,你应该写:
thread.threadname = "Wrong";
答案 1 :(得分:2)
<强> TL;博士强>
memcpy()
指针上的const
(未定义的行为)与写时复制优化相冲突。
是的,vector::push_back()
将对象的副本推送到向量中。因此,在push_back()
编辑本地thread_info
对象后,对本地对象的更改不应该影响向量中的对象,对吗?
但是,std::string
允许假设对其的任何访问都将以明确定义的方式发生。对memcpy()
返回的{const
)指针执行.c_str()
定义不明确。
所以......让我们说std::string
在将thread_info
对象复制到向量时采用了一种捷径:它不是复制包含的数据,而是复制了指针数据,以便两个std::string
对象引用相同的内存区域。
它可以将复制推迟到实际变得必要的时间(如果),即当通过任何定义的函数(如string::insert()
或operator+=
)写入其中一个字符串时。这称为“写时复制”,这是一种相当常见的优化。
通过从const
的返回值中删除.c_str()
并在其上运行memcpy()
,您就挫败了此机制。由于您没有通过任何可以完成写入时复制的string
成员函数,因此两个对象(应该是不同的)仍然指向相同的数据存储器。
GDB输出,断点位于PushVector()
的最后一行:
(gdb) print &thread
$3 = (thread_info *) 0x7fffffffe240
(gdb) print &myvector[0]
$4 = (thread_info *) 0x605040
两个thread_info
对象不同。
(gdb) print &thread.threadname
$5 = (std::string *) 0x7fffffffe248
(gdb) print &myvector[0].threadname
$6 = (std::string *) 0x605048
两个string
对象也不同。
(gdb) print thread.threadname.c_str()
$7 = 0x605028 "Wrongd1"
(gdb) print myvector[0].threadname.c_str()
$8 = 0x605028 "Wrongd1"
但它们指向相同的内存区域,因为string
对象都没有意识到存在写访问权限,因此没有实际复制数据。