Сегрифтинг удаления указателя класса c ++ - PullRequest
0 голосов
/ 25 октября 2010

У меня есть простой класс с именем object, с которым у меня проблема. Есть один метод, который вызывает segfault, если я его называю. Я не понимаю почему.

typedef class object
{
   private:
      short id;
      std::string name;
      SDL_Rect offset;

   public:
      object();
      object(short i, std::string n);
      ~object();
      object(const object &o);
      object& operator = (const object &o);
      std::string get_name();
      void set_name(std::string n);
} object;

object::object()
{
   id = 0;
   name = "";
   offset.x = 0;
   offset.y = 0;
   offset.w = 0;
   offset.h = 0;
}

object::object(short i, std::string n)
{
   id = i;
   name = n;
   offset.x = 0;
   offset.y = 0;
   offset.w = 0;
   offset.h = 0;
}

object::~object()
{
   delete &offset;
   delete &id;
   delete &name;
}

object& object::operator=(const object &o)
{
   if(this != &o)
   {
      delete &name;
      name.assign(o.name);
      delete &id;
      id = o.id;
      delete &offset;
      offset = o.offset;
   }
   return *this;
}

object::object(const object &o)
{
   id = o.id;
   name = o.name;
   offset = o.offset;
}

// Functions
std::string object::get_name()
{
   return name;
}

void object::set_name(std::string n)
{
   name = n;
}

И мой main.cpp

int main( int argc, char** argv )
{
   struct object *a = new object(0, "test");
   struct object *b = new object(1, "another test");

   printf(a->get_name().c_str());
   printf("\n");
   printf(b->get_name().c_str());
   b = a;
   printf("\n");
   printf(b->get_name().c_str());
   a->set_name("Another test");
   printf("\n");
   printf(a->get_name().c_str());

   delete a;
   printf("\nDeleted a");
   delete b;
   printf("\nDeleted b");

   return 0;
}

Если я позвоню a->set_name("Another test");, я получу ошибку. Если я пропущу вызов, никаких проблем, все работает. Я, вероятно, упускаю что-то простое, но я не могу найти это. Это не вызывает ошибки в назначении, но, если эта строка есть, происходит сбой при удалении указателя.

Ответы [ 3 ]

4 голосов
/ 25 октября 2010

Поскольку вы не new ничего в конструкторе, неправильно delete что-либо в деструкторе. Просто оставьте деструктор пустым, или, что еще лучше, избавьтесь от него полностью. Сгенерированный компилятором деструктор делает именно то, что вы хотите (ничего). Вам также не нужно писать конструктор копирования и оператор копирования вручную, просто выбросьте их.

Также нет необходимости создавать объекты динамически, и печать строк намного проще с собственными средствами ввода / вывода C ++. И вы можете избавиться от перегрузки конструктора аргументами по умолчанию. А передача и возврат строк по ссылке на const более эффективна, чем передача их по значению. И последнее, но не менее важное, давайте будем правильными. Вот моя очистка вашего кода:

#include <iostream>

class object
{
    short id;
    std::string name;
    SDL_Rect offset;

public:

    object(short i = 0, const std::string& n = "");
    const std::string& get_name() const;
    void set_name(const std::string& n);
};

object::object(short i, const std::string& n) : id(i), name(n)
{
    offset.x = 0;
    offset.y = 0;
    offset.w = 0;
    offset.h = 0;
}

const std::string& object::get_name() const
{
    return name;
}

void object::set_name(const std::string& n)
{
    name = n;
}

int main(int argc, char** argv)
{
    object a(0, "test");
    object b(1, "another test");

    std::cout << a.get_name() << "\n";
    std::cout << b.get_name() << "\n";

    b = a;
    std::cout << b.get_name() << "\n";

    a.set_name("Another test");
    std::cout << a.get_name() << "\n";
}
3 голосов
/ 25 октября 2010
delete &name;

Вы можете только delete указатели, которые вы получили, позвонив new.name - переменная-член класса;Вы не можете удалить это, и вам никогда не придется.Когда класс будет уничтожен, он также уничтожит все переменные-члены.

Только если у вас есть члены, которые являются указателями (например, если у вас есть std::string* name), вы должны быть уверены, что правильно очистите ихвверх, но даже тогда вы должны предпочесть использовать умные указатели, такие как scoped_ptr, shared_ptr или unique_ptr (если ваша реализация поддерживает это).

0 голосов
/ 25 октября 2010

name является string и управляет собственной памятью.Ваше объявление в структуре правильное, вы можете просто assign превысить любое значение, которое уже есть.Нет необходимости делать что-либо, когда структура выходит из области видимости.

Обратите внимание, что ваш метод get_name возвращает новую копию, поскольку он возвращает значение.Вместо этого вы могли бы вернуть ссылку на то, что находится в структуре, как это, при условии, что возвращаемое значение не используется после того, как собственная структура выходит из области видимости:

const string& get_name() { return name; }

Вы должны изменить объявление сеттера следующим образом, так как естьпередача копии бесполезна (чрезмерная передача по значению является распространенной ошибкой среди новых разработчиков C ++).

void set_name(const string& newValue)
...