Комментарии 10
Из существенного:
Исправленный код:
VltShaderConstData& VltShaderConstData::operator=(VltShaderConstData&& other)
{
if (this == &other)
{
return *this;
}
Имеет смысл заранее убрать грабли на случай перегрузки (возможно, в будущем) унарной операции &
:
VltShaderConstData& VltShaderConstData::operator=(VltShaderConstData&& other)
{
if (this == std::addressof(other))
{
return *this;
}
Согласен, спасибо за ваш комментарий. Поправил код в статье.
это имеет смысл только в шаблонах. Если у вас уже есть тип и вы его контролируете(он ваш), нет никакого смысла делать addressof, кроме разве что следования стилю, не понимаю как это можно называть "существенным"
Если у вас уже есть тип и вы его контролируете(он ваш), нет никакого смысла делать addressof
Проект может развиваться несколькими разработчиками с разным уровнем владения языком, какие-то люди за время жизни проекта могут уходить, какие-то приходить.
А если "контролирующий" уволился?
Да даже если автор -- один.
Через год-другой он уже может забыть о потенциальной проблеме.
Задач как правило и без этого хватает.
не понимаю как это можно называть "существенным"
Это -- хорошие, хитрые такие "грабли", которые, будучи незамеченными, могут тихо "гадить", не привлекая особого внимания. Такие "грабли" -- это существенно.
Не проще ли один раз написать std::addressof
и забыть о потенциальной проблеме в силу невозможности в этом случае её возникновения, сосредоточившись на задаче, нежели постоянно тратить ресурс мозга на то, чтобы помнить, где и что приходится "контролировать"?
Тем более, что std::addressof
не вносит никакого overhead'а, а начиная с C++17, является ещё и constexpr
.
Ну и что, что поначалу выглядит непривычно и бросается в глаза?
Язык теперь с каждым новым стандартом меняется существенным образом.
Постоянно появляется непривычное, придётся привыкать.
Ну, и в целом, если подходить философски, операция &
здесь используется не в полном, широком смысле операции &
, который она имеет в отношении классов, а в узком смысле получения адреса объекта.
С этой точки зрения std::addressof
подходит явно лучше, нежели операция &
, ибо решает именно эту задачу и ни при каких условиях не может начать решать другую, а за операцией &
приходится постоянно следить, как бы, начиная с некоторого незаметного момента, не случилось так, что она начала вдруг решать несколько другую, более широкую задачу, нежели предполагалось изначально.
Тема осталась не раскрыта. В итоге сможем ли мы когда-нибудь поиграть в «Bloodborne» на PC?
А в чём смысл конструкции
do {
...
} while(false);
? Она же просто один раз выполняется, как и обычный код.
В проекте такая конструкция используется, чтобы сделать ранний выход из функции с одним, написав при этом лишь один return.
Еще такая конструкция может использоваться для объединения нескольких конструкций в одну в макросах.
Пояснение (TL;DR;)
#define FreeMemoryAndExit(p) free((p)); return
void foo()
{
int *ptr = malloc(....);
// Какая-то волшебная логика
// Что-то пошло не так
if (....)
FreeMemoryAndExit(ptr);
// Чудесный код продолжается
}
После макроподстановки получим следующий код:
#define FreeMemoryAndExit(p) free((p)); return
void foo()
{
int *ptr = malloc(....);
// Какая-то волшебная логика
// Что-то пошло не так
if (....)
free((ptr)); return;
// Чудесный код продолжается
}
В итоге чудесный код никогда не выполняется, return всегда безусловный. Теперь воспользуемся do { .... } while (false)
:
#define FreeMemoryAndExit(p) do { free((p)); return; } while (false)
void foo()
{
int *ptr = malloc(....);
// Какая-то волшебная логика
// Что-то пошло не так
if (....)
FreeMemoryAndExit(ptr);
// Чудесный код продолжается
}
И вот что получим после препроцессора:
#define FreeMemoryAndExit(p) do { free((p)); return; } while (false)
void foo()
{
int *ptr = malloc(....);
// Какая-то волшебная логика
// Что-то пошло не так
if (....)
do { free((ptr)); return; } while (false);
// Чудесный код продолжается
}
Теперь освобождение и выход зависят от условия. Чудесный код продолжается. Подобного можно было добиться и просто оборачиванием в фигурные скобки. Но у do { .... } while (false)
и здесь есть преимущество - если кто-то допишет ветку else после макроса, то ничего не сломается.
Используется только в макросах, чтобы ставить в конце "вызова" макроса точку с запятой
Проверяем эмулятор GPCS4, или сможем ли когда-нибудь поиграть в «Bloodborne» на PC