【问题标题】:seg fault on coping std::string in std::vector<char> after pointer casting指针转换后在 std::vector<char> 中处理 std::string 的段错误
【发布时间】:2018-03-22 15:28:41
【问题描述】:

以下代码会导致 g++ 5.4.0 20160609 出现分段错误。但它适用于 vs c++ 11.0

#include <string>
#include <iostream>
#include <vector>

struct fooStruct{
    std::string str;
    fooStruct() : str(std::string("")){}
};

int main()
{
    fooStruct fooObj;

    std::vector<char> cont(sizeof(fooStruct));
    std::cout<<"Size of string = "<<sizeof(std::string)<<std::endl;
    std::cout<<"Size of vec = "<<cont.size()<<std::endl;

    std::cout<<sizeof(fooObj)<<std::endl;

    char* ptr = cont.data();
    ((fooStruct*)(ptr))[0] = fooObj;            //segmentation fault
    //((fooStruct*)(ptr))[0].str = fooObj.str; //segmentation fault

    std::cout<<((fooStruct*)(ptr))[0].str<<std::endl;

    return 0;

}

编译器之间的唯一区别是 msvc 需要 40 个字节作为字符串,而 gcc 只需要 32 个字节。但我认为这并不重要。 为什么在msvc上可以,在g++上不行?

【问题讨论】:

  • 你的问题是什么?
  • 我猜这就是他出现分段错误的原因。
  • ((fooStruct*)(ptr))[0] = fooObj; 不是直接违反了严格的别名和调用 UB 吗?
  • “它可以工作”并不意味着它不是未定义的,分配给不存在的东西是未定义的。

标签: c++ visual-studio gcc


【解决方案1】:

您的代码具有未定义的行为。这意味着它可以“工作”或崩溃,两者都是有效的结果。

ptr 指向一个字符数组。它不代表fooStruct。所以当你这样做时

((fooStruct*)(ptr))[0]

您将该内存视为fooStruct,即使它不是未定义的行为。

【讨论】:

  • @juanchopanza 是吗?他们确实使用sizeof(fooStruct) 来表示char 的数量。
  • 是的,你是对的。字符串副本也有问题。
  • 是的。我认为我的答案已经涵盖了这一点,因为如果 ((fooStruct*)(ptr))[0] 是 UB,那么 ((fooStruct*)(ptr))[0].anything 也是 UB。
  • 需要注意的是,即使内存没有指向fooStruct,也可以通过在该位置构造fooStruct对象,通过placement new来实现。然后取消引用以及分配将是完美定义的行为。
  • @Sklert 如果结构是 POD 类型,那么只要底层数组正确对齐就可以了。我不确定它是否会,但我倾向于它不可能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-10
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 1970-01-01
相关资源
最近更新 更多