Как перегрузить указатель на строку, включенную в виртуальный класс

Код на польском языке, извините за то, что это необходимо. У меня проблема с оператором перегрузки "=". Просто взгляните на код

kolo& operator=(const kolo& ref){
if(this!=&ref){
  delete kolor;
  kolor=new string(ref.kolor);
  r=ref.r;
}
return *this;

}

Там у меня ошибка, я пытаюсь что-то еще, как это

kolo& operator=(const kolo& ref){
if(this!=&ref){
  delete kolor;
  *kolor=*ref.kolor;
  r=ref.r;
}
return *this;
}

Это работает (компиляция), но у меня есть утечки памяти, как. Может ли кто-нибудь помочь мне с этим, ниже весь код из класса Figura и класса Коло. Благодарю.

    class figura{
protected:
string *kolor;
public:
  figura():kolor(new string("nic")){}
  figura(const string& a1):kolor(new string(a1)){}
  virtual double pole()const=0;
  virtual void wypisz(ostream& out)const{
    out<<*kolor;
  }
  friend ostream& operator<<(ostream& out,const figura& r);
  virtual ~figura(){delete kolor;}
};

    class kolo:public figura{
protected:
  unsigned r;
public:
  kolo():figura(),r(0){}
  kolo(const string& a1,const unsigned a2):figura(a1),r(a2){}
  kolo(const kolo& ref):figura(ref),r(ref.r){}
  kolo& operator=(const kolo& ref){
    if(this!=&ref){
      delete kolor;
      *kolor=*ref.kolor;
      r=ref.r;
    }
    return *this;
  }
  double pole()const{
    return 3.14*r*r;
  }
  void wypisz(ostream& out)const{
    out<<"Kolor: "<<*kolor<<" "<<"Skladowe: "<<r<<endl;
  }
  friend ostream& operator<<(ostream& out,const kolo& r);
};

Я добавляю проверку на утечку от Valgrind

    ==1774== Invalid read of size 8
==1774==    at 0x49ABE34: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
==1774==    by 0x10AB7F: figura::~figura() (test.cpp:14)
==1774==    by 0x10B155: kolo::~kolo() (test.cpp:20)
==1774==    by 0x10A7B4: main (test.cpp:84)
==1774==  Address 0x4dc1c80 is 0 bytes inside a block of size 32 free'd
==1774==    at 0x483C1CF: operator delete(void*, unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1774==    by 0x10AB8C: figura::~figura() (test.cpp:14)
==1774==    by 0x10B155: kolo::~kolo() (test.cpp:20)
==1774==    by 0x10B175: kolo::~kolo() (test.cpp:20)
==1774==    by 0x10A78B: main (test.cpp:102)
==1774==  Block was alloc'd at
==1774==    at 0x483AE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1774==    by 0x10AAD8: figura::figura(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (test.cpp:8)
==1774==    by 0x10AC27: kolo::kolo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int) (test.cpp:25)
==1774==    by 0x10A467: main (test.cpp:84)
==1774== 
==1774== Invalid free() / delete / delete[] / realloc()
==1774==    at 0x483C1CF: operator delete(void*, unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1774==    by 0x10AB8C: figura::~figura() (test.cpp:14)
==1774==    by 0x10B155: kolo::~kolo() (test.cpp:20)
==1774==    by 0x10A7B4: main (test.cpp:84)
==1774==  Address 0x4dc1c80 is 0 bytes inside a block of size 32 free'd
==1774==    at 0x483C1CF: operator delete(void*, unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1774==    by 0x10AB8C: figura::~figura() (test.cpp:14)
==1774==    by 0x10B155: kolo::~kolo() (test.cpp:20)
==1774==    by 0x10B175: kolo::~kolo() (test.cpp:20)
==1774==    by 0x10A78B: main (test.cpp:102)
==1774==  Block was alloc'd at
==1774==    at 0x483AE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1774==    by 0x10AAD8: figura::figura(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (test.cpp:8)
==1774==    by 0x10AC27: kolo::kolo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int) (test.cpp:25)
==1774==    by 0x10A467: main (test.cpp:84)
==1774== 
==1774== 
==1774== HEAP SUMMARY:
==1774==     in use at exit: 32 bytes in 1 blocks
==1774==   total heap usage: 14 allocs, 14 frees, 74,088 bytes allocated
==1774== 
==1774== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1774==    at 0x483AE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1774==    by 0x10AA29: figura::figura() (test.cpp:7)
==1774==    by 0x10ABE1: kolo::kolo() (test.cpp:24)
==1774==    by 0x10A561: main (test.cpp:88)
==1774== 
==1774== LEAK SUMMARY:
==1774==    definitely lost: 32 bytes in 1 blocks
==1774==    indirectly lost: 0 bytes in 0 blocks
==1774==      possibly lost: 0 bytes in 0 blocks
==1774==    still reachable: 0 bytes in 0 blocks
==1774==         suppressed: 0 bytes in 0 blocks
==1774== 
==1774== For lists of detected and suppressed errors, rerun with: -s
==1774== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

Всего 2 ответа


Избавиться от указателя, и так иметь правило 0 :)

class figura
{
protected:
    string kolor;
public:
    figura() : kolor("nic") {}
    /*explicit*/ figura(const string& s) : kolor(s){}
    virtual ~figura() = default;

    virtual double pole()const = 0;
    virtual void wypisz(ostream& out)const { out<< kolor; }

    friend ostream& operator<<(ostream& out,const figura& r);
};

class kolo:public figura
{
protected:
    unsigned r = 0;
public:
    kolo() : figura(), r(0){}
    kolo(const string& s,const unsigned r):figura(s), r(r){}
    kolo(const kolo& ref) = default;
    kolo& operator=(const kolo& ref) = default;
    double pole()const override { return 3.14*r*r; }
    void wypisz(ostream& out)const override {
        std::out << "Kolor: " << kolor << " " << "Skladowe: " << r << std::endl;
    }
    friend ostream& operator<<(ostream& out,const kolo& r);
};

Правило трех гласит, что если вы реализуете любой из деструктора, копирования-назначения или копирования-конструктора, вам нужно реализовать все три. Вы сделали это для kolo , но не для figurea

Где-то в вашем коде kolo создается с помощью копирования (например, внутри вектора) и использует версию по умолчанию для figurea копирования figurea . Это просто скопирует указатель . Теперь исходная строка потеряна, что приводит к утечке. Новая строка указывается дважды, поэтому будет уничтожена дважды. Второе уничтожение - это то, что вызывает неправильное чтение и удаление.

Существуют различные способы реализации копирования-назначения и копирования-конструктора без повторения кода. Попробуйте этот вопрос , например.

Я также ожидал бы, что, поскольку figurea - это тот, который на самом деле имеет kolor , за figurea должно отвечать назначение копии для figurea , а не kolor . Таким образом, если вы извлекаете другой класс из figurea , вам не нужно переопределять копирование kolor .

Похоже, вы должны использовать необработанные указатели, но обычно лучший способ написать управление памятью - не писать управление памятью. Простое использование строки и, следовательно, встроенное управление строкой в ​​памяти сделало бы все намного проще. Кроме того, использование интеллектуальных указателей, таких как shared_ptr позволяет автоматически выполнять копирование и удаление.


Есть идеи?

10000