用包含std::string的memset结构体

21

我有一个非常庞大的结构体,其中整个内容都是标量变量、枚举和标量数组(基于堆栈),除了一个std::string变量。

现在,这里是我的问题...

如果整个结构体的大小为0(就像它只包含标量一样),那么我可以将结构体设置为0吗?或者由于std::string的存在,这种做法不可行?我不确定memset对其内部表示会产生什么影响。

如果您要说它是好还是不好,请解释一下原因-我想知道它为什么是这样的 :)

3个回答

30

不行,这会覆盖字符串的内部状态并导致出现问题。您可以将所有POD内容包装在一个单独的结构中,并将其放入当前结构中,这样您就可以对该结构进行memset操作,并让字符串默认构造。

编辑:仅澄清一下,该字符串几乎肯定会存储指向其分配存储器的指针。 在您执行memset之前,该字符串的构造函数将始终运行(即使您在类型的构造函数中对this执行了memset,字符串的构造函数也将首先运行)。 因此,您将覆盖此指针值,而它将不再指向其存储空间,而是指向NULL或某些几乎肯定无效的值。


1
不争论将std::string设置为0是一个坏主意,但实际上它可能会起作用,假设您的std:string实现在构造时不分配内存。我想大多数std::string都有3个指针(begin、end、capacity)和一个变量表示大小。如果没有进行任何分配,将所有这些指针设置为0应该是安全的。不用说这是不可移植的。 - Praetorian
最好的情况是,通过覆盖指针,您会泄漏字符串分配的任何内存。 - Nemo
1
@Praetorian - 你是对的,但这个想法太糟糕了,我宁愿把它归类为不可行之举。 - Node
1
@Node 我同意。我在发表评论时忘记了另一件事,即如果std::string从带有虚函数的基类派生,则memsetting会覆盖v-table并捣乱。我不确定标准中是否有任何内容防止std::string基类具有虚函数。 - Praetorian

5

以下是一个奇特的想法:假设您的类 Foo 有许多原始成员,在 Foo 的构造函数中保持未初始化状态,除了一个字符串:

class Foo
{
  int a;
  double b;
  std::string s;
};

构造函数 Foo::Foo() 会正确初始化字符串,但它不会关心其他任何事情。所以,在我们构造之前,让我们将内存清零!
void * addr = ::operator new(sizeof(Foo));
std::memset(addr, 0, sizeof(Foo));
Foo * p = new (addr) Foo;

// later

p->~Foo();
::operator delete(addr);

当然,在构造函数中将所有成员变量初始化为零会更加简洁,但也许你有自己的原因不想创建自定义构造函数。

-1

将 std::string 成员归零是非常糟糕的想法,它会导致内存泄漏!千万不要这样做!


2
这个问题多年来已经有了更详细的回答。这并没有为讨论增添任何内容。 - ShadowRanger
1
是的,但我花了2个小时找出漏洞在哪里。我认为,让人们知道它会导致漏洞是很有意思的。 - GamerDeveloper
1
该语句是不正确的。符合规范的实现在这里没有引起泄漏的要求。事实上,语言规范根本没有承诺行为应该是什么样子的。因此,行为是未定义的。泄漏内存是一种有效的未定义行为形式,就像泄漏内存一样是一种有效的形式。 - IInspectable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接