John Cooper
John Cooper

Reputation: 25

Is it okay to memset a struct which has an another struct with Smart pointer member?

Following codeblock is compiling and running okay.

Qeus-1. Is it safe to memset a struct which contains another stuct with smart pointer as a member variable? (like the example code below)

Ques-2. Is it safe to memset a struct which contains smart pointer members?

Following code structure is part of a legacy project where this hierarchical structures have hundreds of other members (POD or non POD memebers)

#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;
}

Upvotes: 0

Views: 589

Answers (2)

Alan Birtles
Alan Birtles

Reputation: 36478

No, never use memset on any structure which is not POD.

However your code isn't doing that, it is only calling memset on _School which is POD as it only contains a pointer, calling memset on _Class or _Globals would have undefined behaviour. However I'd prefer removing the memset and adding a constructor to _School which initialises pSchool to nullptr:

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

You need to use new in C++ code rather than malloc as malloc doesn't call class constructors.

Also note that identifiers starting with underscore followed by an uppercase character are reserved for use by the compiler/standard library.

The complete code would be:

#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;
}

Upvotes: 5

Evg
Evg

Reputation: 26342

To address the second question, if you have a struct

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

that contains a smart pointer as its member, then doing

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

is definitely not safe, because you overwrite g.ptr object of a non-POD type that has already been constructed.

What you could do is something like this:

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);

There is no reason to use memset in this particular example, but it is legal and safe.

Upvotes: 1

Related Questions