为什么我不能在C++中的`std :: map`中存储引用?

ng5*_*000 41 c++ dictionary reference stdmap std

我强调引用不是指针,而是对象的别名.但是,我仍然不明白这对我作为一个程序员究竟意味着什么,即什么是引擎盖下的引用?

我认为理解这一点的最好方法是理解为什么我不能在地图中存储引用.

我知道我需要停止将引用视为指针的语法,只是不确定如何:/

Seb*_*n M 27

他们我理解它,引用被实现为引擎盖下的指针.你不能将它们存储在地图中的原因纯粹是语义上的; 你必须在创建引用时初始化引用,然后再也不能更改引用.这与地图的工作方式不相符.

  • 标准中明确未指明它们是否具有存储.通常它们会这样做,但有时它可以被优化掉. (4认同)
  • @Jaywalker:是的,他们这样做。在生成的汇编代码中,它们被实现为指针。 (2认同)

Mat*_* M. 24

您应该将引用视为'指向非const对象的const指针':

MyObject& ~~ MyObject * const
Run Code Online (Sandbox Code Playgroud)

此外,引用只能构建为存在的某些东西的别名(对于指针来说不是必需的,尽管除了NULL之外是可取的).这并不能保证对象会保持不变(实际上,当通过引用访问对象时,你可能会有一个核心,如果它不再存在),请考虑以下代码:

// Falsifying a reference
MyObject& firstProblem = *((MyObject*)0);
firstProblem.do(); // undefined behavior

// Referencing something that exists no more
MyObject* anObject = new MyObject;
MyObject& secondProblem = *anObject;
delete anObject;
secondProblem.do(); // undefined behavior
Run Code Online (Sandbox Code Playgroud)

现在,STL容器有两个要求:

  • T必须是默认可构造的(参考不是)
  • T必须是可分配的(您不能重置参考,但您可以指定给它的裁判)

因此,在STL容器中,您必须使用代理或指针.

现在,使用指针可能会对内存处理造成问题,因此您可能必须:

不要使用auto_ptr,分配有问题,因为它修改了右手操作数.

希望能帮助到你 :)

  • 小点:这个`MyObject&firstProblem =*((MyObject*)0);`已经是未定义的行为(你没有使用有效对象初始化引用)因此,根据C++标准,这就是允许格式化你的硬盘或其他坏事给你.(鼻子恶魔,有人吗?)但这只是一个非常小的问题,否则你的答案就是一个很好的答案.+1 (3认同)

Mar*_*n B 7

除了语法糖之外,重要的区别在于引用不能更改为引用另一个对象而不是它们初始化的对象.这就是为什么它们不能存储在地图或其他容器中,因为容器需要能够修改它们包含的元素类型.

举例说明:

A anObject, anotherObject;
A *pointerToA=&anObject;
A &referenceToA=anObject;

// We can change pointerToA so that it points to a different object
pointerToA=&anotherObject;

// But it is not possible to change what referenceToA points to.
// The following code might look as if it does this... but in fact,
// it assigns anotherObject to whatever referenceToA is referring to.
referenceToA=anotherObject;
// Has the same effect as
// anObject=anotherObject;
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说听起来不错,除了"容器需要能够修改它们包含的元素类型".这使得听起来好像地图需要能够更改它存储的数据类型,而实际上它只需要能够更改"元素"本身. (2认同)

Eyt*_*tan 7

实际上,您可以在地图中使用引用。我不建议将这个用于大型项目,因为它可能会导致奇怪的编译错误,但是:

    map<int, int&> no_prob;
    int refered = 666;
    no_prob.insert(std::pair<int, int&>(0, refered)); // works
    no_prob[5] = 777; //wont compile!!! 
    //builds default for 5 then assings which is a problem
    std::cout << no_prob[0] << std::endl; //still a problem
    std::cout << no_prob.at(0) << std::endl; //works!!
Run Code Online (Sandbox Code Playgroud)

所以你可以使用 map 但很难保证它会被正确使用,但我用它来处理小代码(通常是有竞争力的)代码