Это нормально, чтобы memset структура, которая имеет другую структуру с членом указателя Smart? - PullRequest
0 голосов
/ 15 января 2020

Следующий кодовый блок компилируется и работает нормально.

Кеус-1. Безопасно ли задавать структуру, которая содержит другую структуру с умным указателем в качестве переменной-члена? (как пример кода ниже)

Ques-2. Безопасно ли задавать структуру, которая содержит элементы умного указателя?

Следующая структура кода является частью унаследованного проекта, в котором у этой иерархической структуры есть сотни других членов (членов 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;
}

Ответы [ 2 ]

5 голосов
/ 15 января 2020

Нет, никогда не используйте memset на любой структуре, которая не POD .

Однако ваш код этого не делает, он только вызывает memset на _School это POD, поскольку он содержит только указатель, вызов memset для _Class или _Globals будет иметь неопределенное поведение. Однако я бы предпочел удалить memset и добавить конструктор в _School, который инициализирует pSchool в nullptr:

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

Вам нужно использовать new в коде C ++ вместо malloc as 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;
}
1 голос
/ 15 января 2020

Чтобы ответить на второй вопрос, если у вас есть структура

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

, которая содержит умный указатель в качестве члена, тогда выполнение

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

определенно не безопасно, потому что вы перезаписать g.ptr объект не-POD типа, который уже был создан.

Что вы можете сделать, это примерно так:

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 в этом конкретном примере, но это законно и безопасно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...