【问题标题】:Why can't I assign this pointer?为什么我不能分配这个指针?
【发布时间】:2016-02-15 23:40:52
【问题描述】:

我有一个类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;
}

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

我不明白为什么我会收到“表达式不可分配”错误。通过仅取消引用“引用”一次,我不应该能够将指针指向我想要的任何地方吗?

【问题讨论】:

  • 尝试分配给*(references) + i 就像尝试分配给i + 5。你打算如何处理这个任务?
  • 在你的构造函数中,你将一个局部指针数组的地址分配给你的成员变量references,一旦构造函数结束,它就会被销毁。
  • 两者都是真实的,只有一个是编译时,另一个是运行时。
  • 动态分配或std::vector.
  • new Reference*[capacity](); 如果你希望它包含nullptrs,它在第一种情况下也没有。不要忘记 delete [] 并且传递给 insert 函数的内容应该有生命周期,只要你需要它。不过,这是一团糟。

标签: c++ pointers


【解决方案1】:

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

您可能想要*(references + i)references[i] 等效项。请选择后者。它们都返回一个左值引用 - Reference *&amp;

【讨论】:

    【解决方案2】:

    这是一个糟糕的开始:

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

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

    相反,您需要对数组使用动态分配。最好的方法是使用一个管理动态分配的类。你可以自己写,但标准库中已经有一个可以做到这一点,它被称为std::vector。您可以将 References **references; 替换为 std::vector&lt;Reference *&gt; references;

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

    你从来没有初始化它们中的任何一个,所以它们都是野指针。您需要使用初始化程序将它们设置为 null。但是,如果您遵循我的矢量建议,则无需执行此操作;增长一个向量会导致新项目被正确初始化。 (在指针的情况下默认为空指针)。

    insert 函数可以保持原样(括号固定,如其他答案所示);然而,它会导致更整洁的代码来根据需要增长向量,而不是进行空指针搜索。

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


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

    insert(Reference &reference)
    

    原因是,按照惯例,一个通过引用接受某物的函数不应该存储对该对象的任何引用;它应该只在函数执行期间访问对象。否则,您可能会再次生成悬空引用。例如考虑以下代码:

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

    现在管理器将包含一个悬空引用,因为bob 已被销毁,但 bob 的地址仍在管理器内部。这会导致灾难。

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

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

    但至少这更有可能向阅读您的代码且熟悉我所描述的约定的人发出危险信号。

    预计传递&amp;bob可能会存储地址;但是传递bob 会存储一个副本。


    回顾一下;重要的是要考虑您的 ReferenceManager 所指对象的生命周期。你基本上有两个选择:

    • 经理还管理生命周期
    • 生命周期在其他地方进行管理,您确保永远不会在管理器持有对对象的引用时销毁对象。

    第一个选项是让您的容器存储智能指针

    【讨论】:

    • 谢谢!我必须重新阅读才能获得所有内容,非常好的提示,谢谢!
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-30
      • 2018-01-22
      • 2018-05-27
      • 1970-01-01
      • 2017-12-11
      • 2012-01-10
      相关资源
      最近更新 更多