简体   繁体   English

为什么编译器允许C ++中的vector.begin()= vector.end()?

[英]Why does the compiler allow vector.begin()=vector.end() in C++?

While learning about iterators in C++ I tried the following: 在学习C ++中的 迭代器时 ,我尝试了以下方法:

#include <vector>

int main() {
    std::vector<int> a;
    a.end()=a.begin();
    //Why is this even allowed by the compiler?
}

What am I missing? 我错过了什么?

it would not be posiible if for example function end would return a pointer. 如果例如函数end将返回指针,那么它将不可用。

For example this code will not be compiled 例如,不会编译此代码

int a[] = { 1, 2, 3 };

std::end( a ) = std::begin( a );

GCC issues error GCC发出错误

error: lvalue required as left operand of assignment
  std::end( a ) = std::begin( a );
                ^

However when objects of class types are used then they can call the ovetloaded copy (or move) assignment operator. 但是,当使用类类型的对象时,它们可以调用ovetloaded复制(或移动)赋值运算符。

So the question arises why do not the functions return constant iterator objects. 所以问题出现了为什么函数不返回常量迭代器对象。 I think that it would be possible to apply operator ++ . 我认为应用operator ++是可能的。 For example 例如

auto it = ++c.begin();

For direct access iterators as pointers you can write simply 对于直接访问迭代器作为指针,您可以简单地编写

auto it = begin( a ) + 1;

The standard doesn't specify whether std::vector::iterator is a class type, or a raw pointer. 该标准未指定std::vector::iterator是类类型还是原始指针。

If it is a class type then this code calls operator= on the temporary object returned by a.end() . 如果它是类类型,则此代码在a.end()返回的临时对象上调用operator= Not a very useful operation, but legal. 不是一个非常有用的操作,但合法。 (Rvalues may have functions called on them). (Rvalues可能有调用它们的函数)。

If your library makes std::vector::iterator be a pointer then this code would fail to compile, since simple assignment requires an lvalue on the left. 如果你的库使std::vector::iterator成为一个指针,那么这个代码将无法编译,因为简单的赋值需要左边的左值。

Jarod42 pointed out that if the iterator's assignment operator had been defined as: Jarod42指出,如果迭代器的赋值运算符被定义为:

std::vector::iterator& std::vector::iterator::operator =(std::vector::iterator) &;

then this code would be illegal; 那么这段代码就是非法的; the trailing & means that the function is only selectable when it is being called on an lvalue. 尾随&表示该函数仅在左值上调用时才可选。

But it wasn't defined that way, I would guess that the Committee didn't want to make some legal code illegal for no good reason; 但是没有这样定义,我猜想委员会不想因为没有充分理由而使一些法律法规成为非法; maybe there is a use case for it that nobody thought of yet. 也许有一个用例,没人想到。

The line affect a temporary iterator, and so is useless. 该行影响临时迭代器,因此没用。

std::vector::iterator = std::vector::iterator is allowed. 允许使用std::vector::iterator = std::vector::iterator

A way to disallow that would be to have 一种不允许的方式就是拥有

std::vector::iterator::operator =(std::vector::iterator) &; // note the extra &

but std::vector::iterator may be a simple pointer, and we can't disalow T* = T* 但是std::vector::iterator可能是一个简单的指针,我们不能拒绝T* = T*

You cannot assign to an rvalue (aka temporary) primitive type in C++, like (int)7 or a pointer returned by-value from a function. 您不能在C ++中分配rvalue(aka temporary)原语类型,如(int)7或函数返回的值。 This makes lots of sense, as the result of the assignment would be immediately discarded, so it is probably not what the programmer wanted. 这很有意义,因为赋值的结果会被立即丢弃,所以它可能不是程序员想要的。 rvalue means 'right hand side of the = sign' from language grammars, or a temporary (anonymous) value. rvalue表示语言语法中“ = sign”的右侧,或临时(匿名)值。

However on objects of class type, = just invokes operator= . 但是对于类类型的对象, =只调用operator= Usually when the lhs is an rvalue, this would make no sense, but sometimes it would (say, the class is a proxy object pseudo-reference (like what [] on std::vector<bool> returns). So it is treated nit at all special, it just invokes the method. And there was no way to tell if the method was invoked from a temporary rvalue or a 'real' lvalue. 通常当lhs是rvalue时,这没有任何意义,但有时它会(比如,类是一个代理对象伪引用(就像std::vector<bool>上的[]返回)。所以它被对待特别是,它只调用方法。而且无法判断方法是从临时右值还是“真正的”左值调用的。

rvalue references are new in C++11, as are rvalue qualified methods. rvalue引用是C ++ 11中的新增内容,rvalue限定方法也是如此。

Prior to C++11, there was no way to block calling operator= on an object of class type just because it was a temporary. 在C ++ 11之前,没有办法阻止在类类型的对象上调用operator=只是因为它是临时的。

As begin returns a non-const temporary, if it is of class type (not guaranteed by the standard) it can be assigned to. begin返回一个非const临时,如果它是类类型(不是标准保证),它可以被赋值。

Today we can block assignment to temporaries of class type, but the standard library has not been modified to block it on its types. 今天我们可以阻止分配给类类型的临时代码,但是标准库还没有被修改以阻止它的类型。 Probably at least partly to avoid backwards compwtibility issues, and partly to determine best practices outside std first. 可能至少部分是为了避免向后兼容性问题,部分是为了首先确定std之外的最佳实践。

They are allowed because the iterator objects are copy-assignable and copy-constructible. 它们是允许的,因为迭代器对象是可复制分配和可复制构造的。 That is why we can do something like a.begin() = a.end(). 这就是为什么我们可以做类似a.begin()= a.end()的事情。 Also, we can do something auto it(a.begin()). 此外,我们可以自动执行它(a.begin())。

Check the examples below regarding copy-assignable. 请查看以下有关可复制的示例。

#include <vector>

struct CopyConsAssignable
{
    int x;
    CopyConsAssignable(int a) 
    { 
        x = a; 
    }

    CopyConsAssignable(const CopyConsAssignable& other)
    {
        x = other.x;
    }

    CopyConsAssignable& operator=(const CopyConsAssignable& other)
    {
        if (this != &other)
        {
            x = other.x;
        }
        return *this;
    }
};


int main()
{
    std::vector<int> a;
    a.begin() = a.end();

    CopyConsAssignable(2) = CopyConsAssignable(4); // Allowed as the objects are copy-assignable
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM