简体   繁体   English

尽管右侧有异常,但仍发生C ++中的赋值

[英]Assignment in C++ occurs despite exception on the right side

I have some (C++14) code that looks like this: 我有一些(C ++ 14)代码看起来像这样:

map<int, set<string>> junk;
for (int id : GenerateIds()) {
    try {
        set<string> stuff = GetStuff();
        junk[id] = stuff;
    } catch (const StuffException& e) {
        ...
    }
}

This works. 这可行。 Sometimes GetStuff() throws an exception, which works fine, because if it does, I don't want a value in the junk map then. 有时GetStuff()会引发一个异常,该异常可以正常工作,因为如果发生异常,那么我就不需要垃圾映射中的值。

But at first I'd written this in the loop, which doesn't work: 但是起初我是在循环中编写此代码的,这是行不通的:

junk[id] = GetStuff();

More precisely, even when GetStuff() throws an exception, junk[id] is created (and assigned an empty set). 更准确地说,即使GetStuff()引发异常,也会创建junk[id] (并分配一个空集)。

This isn't what I'd expect: I'd expect them to function the same way. 这不是我期望的:我希望它们以相同的方式起作用。

Is there a principle of C++ that I've misunderstood here? 这里有我误解的C ++原理吗?

Before C++17 there was no sequencing between the left- and right-hand side of assignment operators. 在C ++ 17之前,赋值运算符的左侧和右侧之间没有顺序。

It's first in C++17 that explicit sequencing was introduced (right-hand side is evaluated first). 在C ++ 17中,首先引入了显式排序(首先评估了右侧)。

That means the evaluation order is unspecified , which means it's up to the implementation to perform the evaluation in the order in which it wants, and in this case it evaluates the left-hand side first. 这意味着未指定评估顺序,这取决于实现以所需的顺序执行评估,在这种情况下,它将首先评估左侧。

See this evaluation order reference for more details (especially point 20). 有关更多详细信息,请参见此评估订单参考 (尤其是要点20)。

std::map::operator[] std :: map :: operator []

Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist. 返回对该值的引用,该值映射到与键等效的键,如果该键尚不存在,则执行插入。

junk[id] causes the above mentioned insertion and after that has already happened GetStuff() throws. junk[id]导致上述插入,此后已经发生GetStuff()抛出。 Note that in C++14 the order in which these things happen is implementation defined so with a different compiler your junk[id] = GetStuff(); 请注意,在C ++ 14中,发生这些事情的顺序是由实现定义的,因此使用其他编译器,您的junk[id] = GetStuff(); may not do the insertion if GetStuff() throws. 如果GetStuff()抛出,则可能不会执行插入GetStuff()

You're misunderstanding how operator[] works on std::map . 您误解了operator[]std::map

It returns a reference to the mapped item. 它返回对映射项的引用。 Therefore, your code is first inserting a default item in that position and then invoking operator= to set a new value. 因此,您的代码首先是在该位置插入默认项,然后调用operator=设置新值。

To make this work the way you expect, you'll need to use std::map::insert (*): 要按照您期望的方式工作,您需要使用std::map::insert (*):

junk.insert(std::make_pair(id, GetStuff()));

Caveat : insert will only add the value if id is not already mapped. 注意 :如果id尚未映射,则insert将仅添加值。

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

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