引用的工作方式与指针非常相似,但引用总是指向某个实际值。
因此,当operator[] 返回一个引用并且您分配给该引用时,您将直接分配给该引用所引用的值。在您的示例中,这将是位于索引 2 处的对象。请注意,Container::operator[] 的返回类型不是对 Container 的引用,而是通常是对包含值的引用。
要给出详细答案,这取决于所讨论类型的operator[] 的实际返回类型。如果返回类型是对原始类型的引用,那么它就像对原始类型的任何其他引用一样工作。不涉及析构函数。赋值直接在引用的值中进行。例如:
int x = 5;
x = 6;
不调用析构函数。不调用任何运算符。 x 包含的值被赋值运算符右侧的值替换。
如果涉及到引用,则类似:
int x = 5;
int &r = x;
r = 6;
不调用析构函数。不调用任何运算符。 r 指向的值(在本例中为 x)被赋值运算符右侧的值替换。
同样,如果涉及非原始类型,则将调用给定类型的operator=。
Foo x;
Foo y;
// Foo::operator=(const Foo &) is called on x with an argument referencing y
x = y;
x 和 y 的析构函数都不会被调用。
与参考相同:
Foo x, y;
Foo &r = x;
// Foo::operator=(const Foo &) is called on x with an argument referencing y
r = y;
但是,operator[] 不是必需 来返回引用;不过,强烈建议这样做。
对于非引用或对非原始类型的引用,调用返回值的operator=,因此赋值运算符的行为也很重要。
在operator= 的情况下,左侧的析构函数未被调用,但赋值运算符本身负责任何清理工作。这就是为什么赋值运算符通常根据copy-swap idiom 来实现。
所以对于std::vector<int>,std::vector<int>::operator[] 返回一个int &。分配发生在参考点所在的位置。
对于std::vector<Foo>,std::vector<Foo>::operator[] 返回一个Foo & 并调用Foo::operator=(const Foo &)。
然而,就像我提到的,一个类可以从operator[] 返回一个任意对象,并且该对象的赋值运算符将被调用。这可用于通过另一个对象代理分配。您可能会在一个返回 Row 对象的 Matrix 类中看到这一点,该对象又可能实现operator[]。同样,不一定推荐这种设计,但并非闻所未闻。在这些情况下,返回类型可能根本不是引用,而是实际值。然而,它仍然以同样的方式工作。 Row::operator= 或Proxy::operator= 负责分配和清除任何必要的资源。这就是Rule of Three 如此重要的原因。