c ++类指针删除segfaulting

时间:2010-10-25 16:14:52

标签: c++ class pointers segmentation-fault

我有一个名为object的简单类,我遇到了问题。如果我调用它,会导致段错误的一种方法。我不明白为什么。

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 个答案:

答案 0 :(得分:4)

由于构造函数中没有new任何内容,因此析构函数中delete的任何内容都是错误的。只需将析构函数留空,或者甚至更好,完全摆脱它。编译器生成的析构函数完全符合您的要求(没有)。您也不必手动编写复制构造函数和复制赋值运算符,只需将它们丢弃即可。

也不需要动态创建对象,使用本机C ++输入/输出工具打印字符串要容易得多。你可以摆脱使用默认参数重载构造函数。通过reference-to-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";
}

答案 1 :(得分:3)

delete &name;

您只能通过调用delete获得new个指针。 name是该类的成员变量;你不能删除它,也不会删除它。当类被销毁时,它也会破坏任何成员变量。

只有你有成员指针(如果你有std::string* name),你必须确保正确地清理它们,但即便如此,你也应该更喜欢使用智能指针,如{{1 }},scoped_ptrshared_ptr(如果您的实现支持它)。

答案 2 :(得分:0)

namestring并管理自己的内存。您在结构中的声明是正确的,您可以assign在已经存在的任何值之上。当结构超出范围时,无需做任何事情。

请注意,get_name方法返回一个新副本,因为它按值返回。您可以改为返回对结构中的内容的引用,只要在拥有的结构超出范围后不使用返回的值:

const string& get_name() { return name; }

您应该按如下方式更改setter声明,因为传递副本没有任何好处(过多的值传递是新C ++开发人员的常见错误)。

void set_name(const string& newValue)