【问题标题】:C++, Can't use an array or vectors, how do I use a pointer to get through this mess?C++,不能使用数组或向量,如何使用指针来解决这个问题?
【发布时间】:2010-12-18 04:15:48
【问题描述】:

我需要指针和内存管理方面的帮助。

我需要存储不同的对象,它们都派生自同一个基类,并且一直在使用数组来执行此操作,但是当数组中填充了不同的对象时,它会导致分段错误。

当数组中充满了相同派生类型的对象时,我的程序可以正常工作。当数组中填充了不同的对象时,它按预期通过存储在第一个位置的对象工作,但是当它切换到输出第二个对象时,它给了我分段错误。我知道这是一个内存访问问题,但我不清楚我应该如何管理依赖于用户输入的可变数量的对象。

谢谢, 核磁共振

【问题讨论】:

  • 请添加一些代码片段以更好地理解您的问题。
  • 您能否发布一小部分代码,即基类 A、派生类 B、派生类 C,以及您要对它们做什么?
  • std::list 个对象;

标签: c++ arrays memory-management pointers


【解决方案1】:

确保您压入堆栈的指针是动态分配的。以下将失败:

std::vector<Base*> objects;

void make_one(void)
{
    Derived d;

    objects.push_back(&d);
}

因为函数结束时,&amp;d指向的类会被释放。这可以通过动态分配对象来缓解:

std::vector<Base*> objects;

void make_one(void)
{
    Derived *d = new Derived;

    objects.push_back(d); // a-ok
}

完成后请记住检查向量,并在它们上调用delete

struct deleter
{
    template <typename T>    
    void operator()(T* pObject) const
    {
        delete pObject;
    }

}

std::for_each(objects.begin(), objects.end(), deleter());

如果您可以使用 boost,则有一个 pointer container library 可以为您执行此操作。请注意,您不能使用auto_ptr 并尝试让它为您服务; auto_ptr 不适合容器。

另外,请确保您的基类具有虚拟析构函数:

struct base
{
    virtual ~base(void) {} // important!
}

如果不是,则在基类上调用delete 将仅运行基构造函数,从而泄漏派生类可能拥有的任何资源。通过将其设为虚拟,编译器可以跳转到正确的析构函数。

【讨论】:

  • "将只运行基本构造函数" ...产生未定义的行为,IIRC。
  • 更好的是:如果可以,直接使用正确的容器>>boost::ptr_vectorboost.org/doc/libs/1_41_0/libs/ptr_container/doc/…
  • 为了澄清,我们必须动态分配,因为我们正在存储指针,对吧?我们可以将常规对象存储在向量中,而不必担心函数结束时的释放?
  • 您必须动态分配,因为容器比它指向的对象寿命更长。如果您可以保证在对象超出范围之前将指针从容器中删除,则您没有必须动态分配。存储动态分配的指针会移除责任并将其置于容器的保留位置。
【解决方案2】:

我不会发布完整的解决方案,因为您已将问题确定为家庭作业,但我希望我能帮助您解决问题:

数组旨在容纳许多大小相同的对象。在数组中存储不同的对象(即使它们是从同一个基类派生的)的问题是对象可能具有不同的大小。

通过考虑指针,您肯定走在正确的轨道上。

编辑(回应 cmets):

你会看到这样的东西:

BaseClass * array[size];
array[0] = new DerivedClass(...);
array[1] = new OtherDerivedClass(...);
...

这种方法的一个缺陷是没有内置删除数组中的对象。您必须手动循环并调用delete

for (int index = 0; index < size; index++) { delete array[index]; }

【讨论】:

  • 如果我使用一个基类指针数组,每个指针指向一个不同的派生对象,那会起作用吗?我想我已经尝试过该迭代无济于事。或者我是否必须将每个指针的地址存储到所述基指针数组中的派生对象?这是绕口令。
  • 它的语法是什么样的?我相当有信心我的大脑此刻被炸毁了,我无法弄清楚语法。会不会是:Class * Cptr;类 * cptr[大小]; Cptr = new Derived(something, something); std::cout DerivedFunc();类似的东西?
  • 有点。见我上面的回复。另外,睡一觉 :) 早上确实看起来好多了。
  • 不可以用vector吗?这将极大地简化一切。
【解决方案3】:

看起来与这里提到的问题非常相似:Is array of derived same as array of base?。您是否正在创建一个派生对象数组并尝试将其作为基数组进行访问?

您可以像这样使用基指针数组,但请注意最好使用std::vector&lt;Base*&gt; 而不是原始数组:

class Base
{
public:
    virtual ~Base(){}
    virtual void f() {std::cout<<"Base::f()\n";}
};


class Derived1: public Base
{
public:
    ~Derived1(){}
    void f(){std::cout<<"Derived1::f()\n";}
};

class Derived2: public Base
{
public:
    ~Derived2(){}
    void f(){std::cout<<"Derived2::f()\n";}
};


void print(Base** p, int count)
{
    for(int i = 0; i < count; ++i)
    {
        (*p)->f();
        ++p;
    }
}

int main()
{
    Base b;
    Derived1 d1;
    Derived2 d2;

    Base* arr[3];
    arr[0] = &b;
    arr[1] = &d1;
    arr[2] = &d2;

    print(arr, 3);


    return 0;
};

【讨论】:

  • 相反,我创建了一个基础对象数组,并尝试将其作为可变大小的派生对象数组进行访问。从那以后,我意识到这行不通,并试图找出执行基类指针数组的语法。我会查看您发布的链接,该链接看起来很有帮助。
  • 在这种情况下,会发生对象切片(假设您将其作为对象存储在数组中),并且数组中的所有对象实际上都是基类对象。您不能将其强制转换为派生类对象并尝试使用它。
猜你喜欢
  • 2019-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-29
  • 2020-06-07
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
相关资源
最近更新 更多