"как будто" в языковых стандартах
Каково точное значение фразы "как будто" в стандарте и как оно работает, когда пользователь может изменять отдельные части поведения.
Вопрос в том, что касается стандарта С++, когда речь идет о нечерной версии operator new
. 18.4.1.1/7 читает (мой акцент):
Эта новая версия оператора new возвращает указатель, полученный , как если бы был получен из обычной версии.
Мое понимание заключается в том, что "как будто" не требует конкретной реализации, если поведение является подходящим. Поэтому, если operator new
был реализован следующим образом (я знаю, что это не совместимая реализация, поскольку нет цикла или использования new_handler, но я сокращаю это, чтобы сосредоточиться на моей проблеме):
// NOTE - not fully compliant - for illustration purposes only.
void *operator new(std::size_t s)
{
void *p = malloc(s);
if (p == 0)
throw std::bad_alloc();
return p;
}
Тогда было бы законно написать версию nothrow следующим образом:
// NOTE - not fully compliant - for illustration purposes only.
void *operator new(std::size_t s, const std::nothrow_t &nt)
{
return malloc(s);
}
Но скажем, что программа заменяет operator new
на использование другого распределителя. "Как будто" означает, что компилятор должен автоматически изменять поведение версии nothrow для использования этого другого распределителя? Требуется ли разработчик заменить как простые, так и нечеткие версии?
Ответы
Ответ 1
От 1,9 "Выполнение программы:
Соответствующие реализации необходимы для подражания (только) наблюдаемого поведения абстрактной машины
и в информационной сноске:
Это положение иногда называют правилом "как есть", поскольку реализация может игнорировать любое требование настоящего международного стандарта, если результат будет таким, как если бы это требование выполнялось, насколько это может быть определено из наблюдаемое поведение программы. Например, фактическая реализация не должна оценивать часть выражения, если она может вывести, что ее значение не используется и что никаких побочных эффектов, влияющих на наблюдаемое поведение программы, не производится.
В стандарте особо отмечается, что требование "как есть" является обязательным для заменяющей версии версии nothrow operator new()
. Однако, по мере того как я прочитал его, это требование упадет к программисту, переопределяющему operator new()
не компилятор. Оборотная сторона этой ответственности заключается в том, что, по моему мнению, стандарт в значительной степени требует реализации по умолчанию библиотеки nothrow operator new()
, предоставляемой библиотекой, должен что-то делать в соответствии с вызовами металирования new
в try/catch и return 0 if std::bad_alloc
пойман.
Если здесь может возникнуть "как бы правило", если компилятор/компоновщик/все еще достаточно умны, чтобы понять, что при использовании метаданных по умолчанию new()
по умолчанию используется неброска new()
может воспользоваться ярлыком, но если переопределение по умолчанию new()
было переопределено, по умолчанию не бросать new()
пришлось бы действовать по-другому. Я уверен, что это технически возможно для реализации (даже если вы, вероятно, не можете выразить это в стандартном С++). Я был бы удивлен, если бы была такая реализация, которая сделала это.
Я мог бы слишком много читать в этом требовании, но я думаю, что можно сделать вывод.
Ответ 2
Если изменение в распределителе в operator new
делает заметную разницу в поведении совместимой программы на С++, то да, это может потребовать изменения в реализации версии без броска. В частности, если operator delete
ожидает только блоки, выделенные новым распределителем, тогда новое значение no-throw должно измениться.
Мое чтение заключается в том, что использование, как если бы позволяет такую реализацию, как ваша, когда пользователь не переопределяет стандарт operator new
. Как только он появится, реализация не должна использовать no-throw operator new
malloc
и должна либо явно объявить объявленную пользователем, либо хотя бы повторно использовать достаточно объявленной пользователем версии, которую соответствующая программа не может сказать, что это не то, как была реализована версия без броска.
Ответ 3
Разработчик должен заменить как простые, так и нечерные версии. Посмотрите статью на GOTW.
Мое предположение заключается в том, что стандарт ставит требования к реализациям по умолчанию компилятора (и времени исполнения). Таким образом, "как будто" вы цитируете, чтобы сообщить поставщику компилятора, что его реализации по умолчанию этих методов должны соответствовать указанным критериям. Если разработчик решит переопределить только одну версию нового оператора, я не думаю, что ответственность компилятора заключается в том, чтобы сделать все остальные версии оператора новыми. Это ответственность разработчика. Но, что все мое мнение, у меня нет спецификации в данный момент, чтобы увидеть, что она говорит в первом вопросе.