我有一个班级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;只有一次,我不应该把指针指向任何我想要的地方吗?
答案 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时,它变成了一个在内存中没有位置的右值。这是你无法参考的东西。 :)