关于新std :: string实现的memcpy(gcc 5.1)

时间:2015-07-28 06:52:31

标签: c++ gcc g++ stdstring

我编写了以下代码,它似乎与旧的std :: string实现工作正常。但是使用gcc 5.1,它会崩溃。

#include <string>
#include <iostream>
#include <cstring>

struct abc
{
   public:
   abc() {}
   abc(const std::string& x)
      : gullu(x)
   {
   }
   std::string gullu;
};

int main()
{
   abc *a = new abc("dhfghdf");
   abc *b = new abc();
   memcpy((void *)&b, (void *)&a, sizeof(abc));
   std::cout << a->gullu.data() << std::endl;
   std::cout << b->gullu.data();
   return 0;
}

调试它,我发现在执行memcpy之后,对象'a'的内容变成了垃圾。

在建造之后,

  

(gdb)p * a $ 1 = {gullu = {static npos = 4294967295,_M_dataplus =   {&GT; = {&lt; __ gnu_cxx :: new_allocator&gt; = {},},         _M_p = 0x804ea18“dhfghdf”},_ M_string_length = 7,{_M_local_buf =“dhfghdf \ 000 \ 000 \ 000 \ 000 \ 000 \ 000 \ 000 \ 000 \ 000”,_M_allocated_capacity = 1734764644}}}

b建造后

  

(gdb)p * b $ 2 = {gullu = {static npos = 4294967295,_M_dataplus =   {&GT; = {&lt; __ gnu_cxx :: new_allocator&gt; = {},},_ M_p = 0x804ea38“”},       _M_string_length = 0,{_M_local_buf ='\ 000',_M_allocated_capacity = 0}}}

memcpy之后

  

(gdb)p * a $ 4 = {gullu = {static npos = 4294967295,_M_dataplus =   {&GT; = {&lt; __ gnu_cxx :: new_allocator&gt; = {},},         _M_p = 0x666468},_ M_string_length = 2572404,{_ M_local_buf =   “T @'\ 000 \030Ùÿ¿I\ 215 \ 004 \ B \ 001 \ 000 \ 000" ,         _M_allocated_capacity = 2572404}}}

     

(gdb)p * b $ 5 = {gullu = {static npos = 4294967295,_M_dataplus =   {&GT; = {&lt; __ gnu_cxx :: new_allocator&gt; = {},},         _M_p = 0x804ea18“dhfghdf”},_ M_string_length = 7,{_M_local_buf =“dhfghdf \ 000 \ 000 \ 000 \ 000 \ 000 \ 000 \ 000 \ 000 \ 000”,_M_allocated_capacity = 1734764644}}}

我正在使用第三方库,它似乎在做一个memcpy,它正在使用以前的编译器而不使用gcc 5.1因为这个问题

有人可以帮我这个吗?

3 个答案:

答案 0 :(得分:3)

嗯,你没有做你想做的事。虽然您显然正在尝试将string的内容复制到另一个,但您正在做的只是将指针(a)的值复制到另一个(b),但是复制错误的尺寸!

顺便说一句,你的意图是memcpy(b, a, sizeof(abc));,但这不应该也可以工作(虽然它会在几个案例中起作用)!正如我在我的皮肤上学到的(并且感谢this answer),你不能memcpy一个具有非平凡初始化的对象。通过重复使用这样一个对象的存储,你可以终止它的生命周期,但只是memcpy它就不会复活它,所以b所指向的对象将不会活着

来自C ++ 11标准的引言(§3.8对象生存期 [basic.life] ):

  

对象的生命周期是对象的运行时属性。据说一个对象具有非平凡的初始化   如果它是一个类或聚合类型,它或它的一个成员是由一个非常重要的构造函数初始化的   默认构造函数。 [注意:通过简单的复制/移动构造函数进行初始化是非平凡的初始化。 -   结束注释]类型T的对象的生命周期开始于:    - 获得具有适当对齐和T型尺寸的存储, 和    - 如果对象具有非平凡的初始化,则其初始化完成。   类型T的对象的生命周期在以下情况下结束:    - 如果T是具有非平凡析构函数(12.4)的类类型,则析构函数调用开始,或者    - 对象占用的存储空间被重用或发布 。   §

答案 1 :(得分:2)

你正在复制sizeof(abc)字节的数据,但你给memcpy的指针指向ab的指针,而不是对象 - 这里的地址{{ 1}}肯定是错的。

但是你真的不应该这样做,因为复制像这样的对象而不是使用它们复制ctor或其他适当的方法将导致崩溃和未定义的行为。在这种特定情况下,如果字符串有点长,可能会发生两个(void*)&a对象指向同一个堆块,因此您将获得退出范围的双重删除,这是一个不可恢复的崩溃。 / p>

答案 2 :(得分:2)

您的代码触发了未定义的行为,因为您向指针b的地址复制的字节多于指针的大小:您正在复制sizeof(abc)而不是sizeof(a)