将取消引用的对象分配给对象会导致 seg 错误

Assignment of dereferenced object to an object causes seg fault

本文关键字:对象 seg 错误 分配 取消 引用      更新时间:2023-10-16

我有以下简单的程序作为说明:

#include <string>
using namespace std;
int main()
{
    string name;
    string *my_str;
    name = "foo";
    my_str = (string *) malloc(sizeof(*my_str));
    *my_str = name;                           // fault line
    // my_str = new(my_str) string(name);     // fix
}

代码编译,但在执行过程中出现 seg 错误:

$ ./a.out
Segmentation fault (core dumped)
$ gdb -q ./a.out ./core.31114
.....
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  __exchange_and_add_single (__mem=<optimized out>, __val=-1)
    at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/ext/atomicity.h:66
66      /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/ext/atomicity.h: No such file or directory.
(gdb) bt
#0  __exchange_and_add_single (__mem=<optimized out>, __val=-1)
    at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/ext/atomicity.h:66
#1  __exchange_and_add_dispatch (__mem=0xfffffffffffffff8, __val=<optimized out>)
    at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/ext/atomicity.h:83
#2  std::string::_Rep::_M_dispose (this=0xffffffffffffffe8, __a=...)
    at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/bits/basic_string.h:242
#3  0x00007fbab7a5ff06 in _M_grab (__alloc1=..., this=<optimized out>, __alloc2=...)
    at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/bits/basic_string.h:226
#4  _M_grab (__alloc2=..., __alloc1=..., this=<optimized out>)
    at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:244
#5  std::string::assign (this=0x99a040, __str=...) at /home/packages/gcc/4.7/w/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:251
#6  0x00000000004008b3 in main () at ./strassign.cc:12

我知道问题的解决方法(用字符串"fix"注释的行),我也知道我应该首先使用new。 这是一个虚构的例子。 我在调试一大段代码时遇到了这个问题,我(目前)没有兴趣通过并用新的替换所有 malloc。

我只是想了解引擎盖下(基本上是对 bt 的解释)为什么分配 seg 出错。 我在想会调用对象 *my_str 的字符串复制赋值运算符,一切都应该解决。 但根据结果,我想不会。 任何见解将不胜感激。

谢谢艾哈迈德。

my_str = (string *) malloc(sizeof(*my_str));

这会为堆上的string分配空间(而不是在C++免费存储区)。

做的是初始化内存。
因此,虽然我们现在有足够的空间来string,但我们没有string

您的修复

my_str = new(my_str) string(name);
// Should cast the pointer-argument to `void*` before giving it to `new`.
// Otherwise, some other custom overload of `operator new` might match better.

使用 placement-new-expression 调用构造函数,并建立对象不变量(从而开始string -objects 生存期)。

顺便说一句:constexpr void* operator new(size_t, void*)被定义为只返回它的第二个参数,所以只有新表达式的第二部分,ctor-call,有任何影响。

如果您希望my_str指向与名称相同的数据,那么您想要的是

my_str = &name;

而且不需要马洛克。如果要复制它,请使用strcpy(在C中)或您显示为C++修复的行。

现在,您正在尝试将my_str指向的数据设置为字符串对象(分配指向取消引用值的指针)。

表达式(如std::string* myString = new myString("hello"));)执行两个步骤。首先,它为对象分配内存,然后调用构造函数来初始化对象。 当您使用 malloc 分配内存时,您拥有对象本身的内存,但它不会以任何方式初始化......只是任何任意的记忆恰好在那里。

std::string的情况下,实际的字符串数据是单独分配的。 当您分配给对象时,它将尝试将数据复制到对象内数据指针中的任何位置,这可能不是您的。

通过调用放置 new,您将调用构造函数来初始化已单独分配其内存的对象。