为什么我不能分配这个指针?

时间:2016-02-15 23:40:53

标签: c++ pointers

我有一个班级ReferenceManager(一个处理书籍或期刊引用的班级),其中包含数据成员:

private:
    int arraySize;
    Reference **references;

这是" ReferenceManager"的主要构造函数:

ReferenceManager::ReferenceManager(int capacity):
arraySize(capacity)
{
    Reference* arrayOfreferencePointers[capacity];
    references = arrayOfreferencePointers;
}

Reference是我创建的另一个课程。

所以,根据我的理解,现在我们有一个指针Reference **references,它指向Reference*的指针数组。所有这些指针现在都指向NULL

到目前为止一切顺利。

现在,考虑ReferenceManager类的这个成员函数:

bool ReferenceManager::insert(Reference &reference){
    for (int i = 0; i < arraySize; i++) {
        if((*(references) + i) == NULL){
            (*(references) + i) = &reference; //ERROR: expression not assignable
            cout << "Object placed in position " << i << "." << endl;
            return true;
        }
    }
    cout << "Array full!" << endl;
    return false;
}

此函数假设获取数组中的第一个可用指针,并将其指向通过引用传递的对象。

我不明白为什么我得到一个不可分配的表情&#34;错误。通过解除引用&#34;引用&#34;只有一次,我不应该把指针指向任何我想要的地方吗?

3 个答案:

答案 0 :(得分:3)

这是因为(*(references) + i)会产生您无法分配的rvalue。它相当于(references[0] + i)

您可能希望*(references + i)references[i]等效。请选择以后的。它们都返回左值引用 - Reference *&

答案 1 :(得分:2)

这是一个糟糕的开始:

ReferenceManager::ReferenceManager(int capacity):
arraySize(capacity)
{
    Reference* arrayOfreferencePointers[capacity];
    references = arrayOfreferencePointers;
}

您已在函数中声明arrayOfreferencePointers。这称为自动变量,当函数退出时会被销毁。这将使您的班级成员references成为悬空指针,即不指向有效对象的指针。

相反,您需要为数组使用动态分配。执行此操作的最佳方法是使用管理动态分配的类。你可以编写自己的,但是已经有一个在标准库中执行此操作,它被称为std::vector。您可以将References **references;替换为std::vector<Reference *> references;

  

所有这些指针现在都指向NULL。

你从来没有初始化过它们,所以它们都是狂野的指针。您需要使用初始化程序将它们设置为null。但是,如果你按照我的矢量建议,那么你不需要这样做;生长向量会导致新项目正确初始化。 (在指针的情况下默认为空指针)。

insert函数可以保留(如同其他答案所示,其中包围固定);但是它会导致更加整洁的代码来增加矢量,而不是进行空指针搜索。

NB。如果你只是在编译时实例化一个大小已知的ReferenceManager,那么这会打开另一种方法:使capacity成为模板参数,并使用类成员数组而不是向量。

现在更全面地谈论设计,这不是一个好主意:

insert(Reference &reference)

原因在于,按照惯例,通过引用接受某个东西的函数不应该存储对该对象的任何引用;它应该只在函数持续时间内访问对象。否则,您可能会再次生成悬空参考。例如,请考虑以下代码:

void func()
{
    Reference bob;
    manager->insert(bob);
    // oops...
}

现在,经理将包含一个悬空引用,因为bob已被销毁但是鲍勃的地址存在于经理内部。这导致了灾难。

为了表明您可以存储对象,最好让插入函数接受指针。这用作函数可以存储指针的自我文档。当然,有人仍然可以写:

Reference bob;
manager->insert(&bob);

但至少这更有可能给那些熟悉我所描述的惯例的人读一个红旗。

预计通过&bob可以存储地址;但是传递bob会存储副本。

重新开始;考虑ReferenceManager所引用的对象的生命周期非常重要。你基本上有两种选择:

  • 经理还负责管理生命周期
  • 在其他地方管理生命周期,并确保在经理持有对象的引用时永远不要销毁对象。

第一个选项是通过让您的容器存储智能指针来完成的。

答案 2 :(得分:1)

引用需要内存位置或左值。虽然*(引用)是左值,但当你将它添加到i时,它变成了一个在内存中没有位置的右值。这是你无法参考的东西。 :)