Вычислительная последовательность присваивания для переменной фундаментального типа с правым операндом, вызывающим исключение - PullRequest
0 голосов
/ 16 января 2019

Если я использую выражение, которое может выдавать, чтобы присвоить значение переменной фундаментального типа , гарантируется ли, что состояние переменной не изменится, если будет выдано исключение?

Например, в следующем коде, если мы выберем «Вариант A», и исключение будет выдано operator new(), существует ли любой шанс того, что переменная-член ptr не будет равна nullptr когда деструктор будет вызываться при разматывании стека?

#include <new>  // operator new   operator delete

class MemoryHolder {
  private:
    void * ptr;

  public:
    MemoryHolder () {
      ptr = nullptr;
    }

    void increase_memory () {
      operator delete (ptr);
      ptr = nullptr;

      // Option A (unsafe?)
      ptr = operator new (10);

      // Option B (safe)
      void * new_ptr = operator new (10);
      ptr = new_ptr;
    }

    ~MemoryHolder () {
      operator delete (ptr);
    }
};

Мне интересно узнать ответ для C ++ 14 и C ++ 17.

Мое предположение: «Вариант A» безопасен в C ++ 14 и C ++ 17, потому что они оба содержат это утверждение (ср. § [expr.ass] ¶ 1):

Во всех случаях присвоение упорядочено после вычисления значения правого и левого операндов

Однако я не уверен, что выполнение «вычисления значения» левого операнда не включает в себя присвоение ему нового значения. Я не нашел определения «вычисления значений» в стандарте.

Связано (но неясно для меня): Назначение в C ++ происходит несмотря на исключение с правой стороны

1 Ответ

0 голосов
/ 16 января 2019

в следующем коде, если мы выбираем «Option A» и исключение выдается operator new(), существует ли any вероятность того, что переменная-член ptr не будет равна nullptr когда деструктор будет вызываться при разматывании стека?

Я на мгновение забуду, что ptr фактически никогда не инициализируется в MemoryHolder до вызова new и, следовательно, может иметь неопределенное значение. Таким образом, ваш вопрос «будет ли ptr иметь то же значение до назначения, что и после?»

В той степени, в которой вы действительно можете это проверить (что в конструкторе означает, что вам фактически нужно перехватить исключение внутри конструктора), да, оно будет иметь то же значение.

Я не нашел определения «вычисления значений» в стандарте.

Хотя стандарт иногда углубляется в странный язык, он не пытается активно обмануть вас . Если термин не определен, то его следует принимать по номиналу. «Вычисление значения» означает ... вычисление значения. Вы назначаете A для B. Это означает, что нужно выяснить, что такое A и B. Что включает в себя вычисление значений для них, а затем выполнение присваивания.

Связанный (но неясный для меня): назначение в C ++ происходит несмотря на исключение на правой стороне

Это не имеет отношения к вашему вопросу, потому что речь идет о порядке «вычисления значения» для обеих сторон назначения, а не о выполнении назначения. ОП этого вопроса ошиблась. Назначение никогда не происходит на самом деле. Просто map::operator[] создаст запись на карте, если она еще не существует. А поскольку в C ++ 14 нет последовательности двух сторон операции присваивания, реализации могут позволять им происходить в любом порядке. И в этом случае operator[] произошло первым, поэтому элемент был вставлен, хотя назначения не было.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...