Интеллектуальные указатели C++ для объектов, содержащих необработанные указатели

У меня есть класс с элементом, который содержит необработанный указатель на другой объект, как показано ниже. Обратите внимание, что пример, который я упростил из моей реальной работы, вероятно, может работать, но я пытаюсь получить концептуальную ошибку, если я делаю здесь, потому что в совершенно той же структуре и сценарии я получаю ошибку ошибки сегментации.

    /*This doesn't have a raw pointer of another object*/
       class H1 {
         private:
          int x, y;
         public:
          constructors;
          copy_constructor;
        }
    /*This has a h1_ptr element which is a raw pointer of H1*/
       class G1 {
         private:
          int count;
          H1* h1_ptr;
         public:
          G1(int c, H1* lst){
           count = 0;
           h1_ptr = lst;
         }
         G1(const G1& g) {
           count = g.count;
           h1_ptr = g.h1_ptr;
         }
         G1& operator=(const G1& g)
         {
           count = g.count;
           h1_ptr = g.h1_ptr;
         }
        }
    /*The class that I create unique_ptr from*/
class H3 {
         private:
          H1 h1, h2;
          G1 g1;
         public:
          H3(H1 _h1, H1 _h2, G1 _g1){
             h1 = _h1; h2 = _h2; g1 = _g1;
          }
        }

Я создаю unique_ptr из класса H3 в функции и возвращаю его другой функции:

unique_ptr<H3> create_ptr(){
      H1 h1(5, 10);
      H1 h2(50, 100);

      H1* h1_lst = new H1[20];
      H1 ls;
      for (int i=0;i<20;i++)
      {
        H1 ls(i, i*2);
        h1_lst[i] = ls;
      } 
      G1 g1(200, h1_lst);
      unique_ptr<H3> p_h3(new H3(h1, h2, g1));
      return p_h3;
    }
 int main(){
   unique_ptr<H3> p_h3 = create_ptr();
   H3* h_3 = p_h3.get();//to get the raw pointer
   G1 g1(h_3->g1);//corrected
   H1* h1_lst = g1.h1_ptr;
   for (int i=0;i< 5; i++){
     //I just want 5 of them even if there is more
     H1 ls = h1_lst[i];
     cout << ls.x << ":" << ls.y << endl;
   }
   return 0;
 }

Это просто напишет 1 или 2 строки, а затем произойдет сбой с ошибкой сегментации. Если бы я не возвращал уникальный указатель, а получал необработанный указатель и вместо этого записывал результат в функцию create_ptr, все работало бы отлично.


person iesiyok    schedule 22.08.2018    source источник
comment
Размещенный код даже не скомпилируется. G1 g1 = h_3->g1; получит нарушение прав доступа. Есть ли причина, по которой вы не используете std::vector? Чтобы найти повреждение памяти, необходимо просмотреть код конструктора и конструкторов копирования.   -  person steve    schedule 23.08.2018
comment
Скажем так: код, который вы показываете, относится к категории, которую вы можете написать на С++ таким образом, если знаете, что делаете. То есть то, что вы показываете, само по себе не является неправильным. Но за словами constructors и copy_constructors вы прячете много кода, и источник ваших проблем весьма скорее всего там.   -  person j6t    schedule 23.08.2018
comment
Я отредактировал код на основе ваших комментариев. Я все еще получаю Thread 1: EXC_BAD_ACCESS (код = EXC_I386_GPFLT) на Xcode и ошибку сегментации на компиляторе gcc. Где вы хотите, чтобы я использовал std::vector?   -  person iesiyok    schedule 23.08.2018
comment
Концептуальная ошибка состоит в том, чтобы в первую очередь использовать необработанные указатели.   -  person n. 1.8e9-where's-my-share m.    schedule 23.08.2018
comment
К сожалению, это не мой выбор, я использую библиотеку, и эти объекты берутся из нее. Это очень сложно и не очень легко изменить.   -  person iesiyok    schedule 23.08.2018
comment
Опубликуйте минимально воспроизводимый пример.   -  person n. 1.8e9-where's-my-share m.    schedule 23.08.2018


Ответы (2)


Проблема заключалась в деструкторе внешнего класса, такого как (G1 в этом примере), который пытался удалить необработанные объекты-указатели. Когда я удаляю эти процессы удаления, все работает нормально, но я считаю, что это все еще плохая идея.

person iesiyok    schedule 29.08.2018

Вы не можете скопировать назначение std::unique_ptr из другого уникального указателя. Это не CopyConstructible или CopyAssignable.

Однако вы можете передать право собственности, используя std::move:

std::unique_ptr iptr1{new int{1}};
std::unique_ptr iptr2 = std::move(iptr1); // iptr1 now null 

Если вы хотите иметь несколько владельцев указателя, используйте вместо этого std::shared_ptr.

Подробнее об этом читайте на странице cppreference std::unique_ptr.

person kaps    schedule 23.08.2018
comment
Если вы имеете в виду вот это назначение: unique_ptr‹H3› p_h3 = create_ptr(); Компилятор даже не жалуется на это. - person iesiyok; 23.08.2018
comment
Вы можете определенно назначить unique_ptr. Вы не можете CopyAssign, но можете MoveAssign. - person rubenvb; 23.08.2018
comment
Назначьте как в unique_ptr‹..› a= b; // где b — еще один уникальный указатель. - person kaps; 23.08.2018