为什么我不能在 C++ 的 `std::map` 中存储引用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1543193/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why Can't I store references in a `std::map` in C++?
提问by ng5000
I understand that references are not pointers, but an alias to an object. However, I still don't understand what exactly this means to me as a programmer, i.e. what are references under the hood?
我知道引用不是指针,而是对象的别名。但是,作为一名程序员,我仍然不明白这对我来说究竟意味着什么,即幕后引用是什么?
I think the best way to understand this would be to understand why it is I can't store a reference in a map.
我认为理解这一点的最好方法是理解为什么我不能在地图中存储参考。
I know I need to stop thinking of references as syntactic suger over pointers, just not sure how to :/
我知道我需要停止将引用视为对指针的句法支持,只是不知道如何:/
采纳答案by Sebastiaan M
They way I understand it, references are implemented as pointers under the hood. The reason why you can't store them in a map is purely semantic; you have to initialize a reference when it's created and you can't change it afterward anymore. This doesn't mesh with the way a map works.
他们按照我的理解方式,引用被实现为引擎盖下的指针。不能将它们存储在地图中的原因纯粹是语义;您必须在创建引用时对其进行初始化,之后便无法再更改它。这与地图的工作方式不符。
回答by Matthieu M.
You should think of a reference as a 'const pointer to a non-const object':
您应该将引用视为“指向非常量对象的常量指针”:
MyObject& ~~ MyObject * const
Furthermore, a reference can only be built as an alias of something which exists (which is not necessary for a pointer, though advisable apart from NULL). This does not guarantee that the object will stay around (and indeed you might have a core when accessing an object through a reference if it is no more), consider this code:
此外,引用只能构建为存在的事物的别名(这对于指针来说不是必需的,尽管除了 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
Now, there are two requirements for a STL container:
现在,对 STL 容器有两个要求:
- T must be default constructible (a reference is not)
- T must be assignable (you cannot reset a reference, though you can assign to its referee)
- T 必须是默认可构造的(引用不是)
- T 必须是可赋值的(你不能重置引用,但你可以赋值给它的裁判)
So, in STL containers, you have to use proxys or pointers.
因此,在 STL 容器中,您必须使用代理或指针。
Now, using pointers might prove problematic for memory handling, so you may have to:
现在,使用指针可能会导致内存处理有问题,因此您可能必须:
- use smart pointers (boost::shared_ptrfor example)
- use a specialized container: Boost Pointer Container Library
- 使用智能指针(例如boost::shared_ptr)
- 使用专门的容器:Boost Pointer Container Library
DO NOT use auto_ptr, there is a problem with assignment since it modifies the right hand operand.
不要使用auto_ptr,赋值存在问题,因为它修改了右手操作数。
Hope it helps :)
希望能帮助到你 :)
回答by Martin B
The important difference apart from the syntactic sugar is that references cannot be changed to refer to another object than the one they were initialized with. This is why they cannot be stored in maps or other containers, because containers need to be able to modify the element type they contain.
除了语法糖之外的重要区别是,引用不能被更改为引用另一个对象而不是它们被初始化的对象。这就是为什么它们不能存储在映射或其他容器中的原因,因为容器需要能够修改它们包含的元素类型。
As an illustration of this:
作为一个例子:
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;
回答by Eytan
actually you can use references in a map. i don't recommend this for big projects as it might cause weird compilation errors but:
实际上,您可以在地图中使用引用。我不建议将这个用于大型项目,因为它可能会导致奇怪的编译错误,但是:
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!!
so you can use map but it will be difficult to guaranty it will be used correctly, but i used this for small codes (usually competitive) codes
所以你可以使用 map 但很难保证它会被正确使用,但我用它来处理小代码(通常是有竞争力的)代码
回答by tcb
A container that stores a reference hasto initialize all its elements when constructed and therefore is less useful.
其存储基准的容器具有构造时初始化其所有元素,因此是不太有用。
struct container
{
string& s_; // string reference
};
int main()
{
string s { "hello" };
//container {}; // error - object has an uninitialized reference member
container c { s }; // Ok
c.s_ = "bye";
cout << s; // prints bye
}
Also, once initialized, the storage for the container elements cannot be changed. s_ will alwaysrefer to the storage of s above.
此外,一旦初始化,容器元素的存储就无法更改。s_总是指上面 s 的存储。
回答by Chethan Ravindranath
This post explains how pointers are implemented under the hood - http://www.codeproject.com/KB/cpp/References_in_c__.aspx, which also supports sebastians answer.
这篇文章解释了如何在幕后实现指针 - http://www.codeproject.com/KB/cpp/References_in_c__.aspx,它也支持 sebastians 的答案。