Copying (using assignment) a structure to a structure inside a union causing seg fault

耗尽温柔 提交于 2019-12-18 09:34:52

问题


I wrote the following code:

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

struct bar
{
  std::string s3;
  std::string s4;
}Bar;

union foo
{
  char * s1;
  char * s2;
  bar    b1;

  foo(){};
  ~foo(){};
}Foo;


int main ()
{
  foo f1;
  bar b2;

  std::string temp("s3");
  b2.s3 = temp;
  b2.s4 = temp;

  //f1.b1 = b2;                           //-- This Fails (Seg faults)

  /*
    #0  0x00002b9fede74d25 in std::string::_Rep::_M_dispose(std::allocator<char> const&) [clone .part.12] ()
        from /usr/local/lib64/libstdc++.so.6
    #1  0x00002b9fede75f09 in std::string::assign(std::string const&) () from /usr/local/lib64/libstdc++.so.6
    #2  0x0000000000400ed1 in bar::operator= (this=0x7fff3f20ece0) at un.cpp:5
    #3  0x0000000000400cdb in main () at un.cpp:31
  */

  memcpy( &f1.b1, &b2, sizeof(b2) );  //-- This Works 

  std::cout << f1.b1.s3 << " " << f1.b1.s4 << std::endl;
  return 0;
} 

Can you please explain why the segmentation fault ? I am unable to decipher what that the data in the back trace suggests.


回答1:


union foo can't initialize the bar object (how does it know which member's initializer to call?) and consequently can't initialize the std::strings. If you want to use the bar inside of foo, then you need to manually initialize it, like so...

new (&f1.b1) bar; // Placement new
f1.b1 = b2;
// And later in code you'll have to manually destruct the bar, because
//   foo doesn't know to destruct the bar either...
f1.b1.~bar();

Alternatively, you can try to roll this functionality into the union's constructors and destructors yourself.

foo() : b1() {}
// Or you construct like this, which you might need to for a non-trivial union...
// foo() { new (&b1) bar; }  // Placement new.
~foo() { b1.~bar(); }

Note that copying also needs special handling.




回答2:


std::string has a non-trivial constructor, that initializes its internal members. Therefore, your struct bar is no POD structure.

Unions only support POD (this is relaxed in C++11). The compiler cannot decide which constructor of which of the union's members to call. Imagine following situation:

unition MyUnion {
  std::string s;
  std::vector v;
};

Should it use vector's or string's constructor to initialize the object?

So in your situation, when you assign the string to the union's string, the internal data is not initalized, which causes random errors.




回答3:


You can't use memcpy to copy objects or structure containing objects because they will not be properly initialized. Strings have pointers to char arrays, and if two strings can share the same pointer, there must be some kind of garbage collection (typically a reference counter). If you do f1.b1 = b2, the compiler will generate the code to initialize the strings correctly.



来源:https://stackoverflow.com/questions/22763191/copying-using-assignment-a-structure-to-a-structure-inside-a-union-causing-seg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!