Reputation: 25
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
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
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