【问题标题】:Is it okay to memset a struct which has an another struct with Smart pointer member?是否可以 memset 一个结构,该结构具有另一个带有智能指针成员的结构?
【发布时间】:2020-01-15 08:06:47
【问题描述】:

以下代码块正在编译和运行正常。

Qeus-1。 memset 一个包含另一个以智能指针作为成员变量的结构的结构是否安全? (就像下面的示例代码)

问题 2。 memset 包含智能指针成员的结构是否安全?

以下代码结构是遗留项目的一部分,其中这种分层结构有数百个其他成员(POD 或非 POD 成员)

#include <iostream>
#include <map>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <memory>


typedef struct _Globals{
  std::shared_ptr<std::map<int, std::string> > rollNamePair;
} _Globals;

struct _Class {
  struct _Globals Globals;  // global vars
};

struct _School {
  struct _Class *pSchool;
};

int main()
{
  struct _School abc;
  memset(&abc, 0, sizeof(struct _School));
  abc.pSchool= (struct _Class*) malloc(sizeof(struct _Class));
  abc.pSchool->Globals.rollNamePair= std::make_shared<std::map<int, std::string> >();
  (*abc.pSchool->Globals.rollNamePair)[1]= "John";
  (*abc.pSchool->Globals.rollNamePair)[2]= "Paul";

  std::cout << (*abc.pSchool->Globals.rollNamePair)[1] << "\n";
  std::cout << (*abc.pSchool->Globals.rollNamePair)[2];

  return 0;
}

【问题讨论】:

  • 不,malloc()struct 与带有构造函数的成员一起使用也不安全!
  • _School 不包含智能指针,它包含一个原始指针。
  • 顺便说一下,这里不需要typedefs 和一半的structs。
  • @Evg,标题已更新
  • 还有像_Globals_School 这样的名称是保留的。也许您是通过查看您的实现标准库来了解它的,它使用像这样丑陋的名称因为它们是为它保留的。

标签: c++ c++11


【解决方案1】:

不,切勿在任何不是POD 的结构上使用memset

但是您的代码没有这样做,它只是在 _School 上调用 memset,这是 POD,因为它只包含一个指针,在 _Class_Globals 上调用 memset 将具有未定义的行为。但是我更喜欢删除 memset 并向 _School 添加一个构造函数,它将 pSchool 初始化为 nullptr

struct _School {
  _Class *pSchool;
  _School() : pSchool(nullptr) {}
};

您需要在 C++ 代码中使用 new 而不是 malloc,因为 malloc 不调用类构造函数。

另请注意,以下划线后跟大写字符开头的标识符保留供编译器/标准库使用。

完整的代码是:

#include <map>
#include <string>
#include <memory>
#include <iostream>

struct Globals{
  std::shared_ptr<std::map<int, std::string> > rollNamePair;
};

struct Class {
  Globals Globals;  // global vars
};

struct School {
  Class *pSchool;
  School() :pSchool(nullptr) {}
};

int main()
{
  School abc;
  abc.pSchool= new Class();
  abc.pSchool->Globals.rollNamePair = std::make_shared<std::map<int, std::string> >();
  (*abc.pSchool->Globals.rollNamePair)[1] = "John";
  (*abc.pSchool->Globals.rollNamePair)[2] = "Paul";

  std::cout << (*abc.pSchool->Globals.rollNamePair)[1] << "\n";
  std::cout << (*abc.pSchool->Globals.rollNamePair)[2];

  delete abc.pSchool;

  return 0;
}

【讨论】:

  • 感谢您的准确回答。我已经更新了问题以使其更清楚。但我相信你的回答对我的问题仍然有效。代码是从我们试图在现代 C++11 中转换的遗留 C 项目中复制的
  • @JohnCooper 我已经为你的第二个问题添加了答案
【解决方案2】:

解决第二个问题,如果你有一个结构

struct G {
    std::shared_ptr<T> ptr;
};

包含一个智能指针作为其成员,然后做

G g;
std::memset(&g, 0, sizeof(G));

绝对不安全,因为你覆盖了已经构造的非 POD 类型的 g.ptr 对象。

你可以这样做:

std::aligned_storage_t<sizeof(G), alignof(G)> storage; // Raw storage of some POD type
std::memset(&storage, 0, sizeof(G));
auto g = new (&storage) G;
g->ptr = std::make_shared ... ;
// ...
std::destroy_at(g);

在此特定示例中没有理由使用memset,但它是合法且安全的。

【讨论】:

    猜你喜欢
    • 2014-06-09
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 2016-09-24
    • 1970-01-01
    • 2014-03-23
    • 1970-01-01
    相关资源
    最近更新 更多