Периодически сталкиваюсь с различными ошибками программистов и особенностями различных компиляторов, поэтому решил это залогировать, не факт, что все вспомню, но как минимум буду пополнять новыми ошибками.
1. Знаковые и беззнаковые типы.
Этот код работает на Visual Studio, но в XCode все отрицательные значение при конвертации в size_t становятся нулями.
size_t i = static_cast<size_t>(double(-1.0)) double d = static_cast<double>((int)i);
Тут сравниваятся разные типы, на это есть предупреждения компилятора, но у меня почему-то компилятор VS не вывел предупреждение, помогло только явное включение предупреждения. А проблема тут в том, что знаковое -1 конвертируется в беззнаковое 0xFFFFFFFF что больше 1.
signed int i = -1; unsigned int u = 1; if ( i > u ) ...
2. Compile-time константы как поля классов.
Пока не появилась поддержка inline для статичных полей класса приходится писать такие конструкции, причем ошибка возникает только в релизной конфигурации. Что интересно, до появления constexpr вариант с static const такого не требовал, хотя по стандарту надо всегда выносить объявление статичных полей из класса если они используются в run-time, например передаются в функции или даже в static_assert, а вот если это значение используется только в рассчетах в compile-time, то выносить объявление не требуется. Подробнее тут.
struct A { template <typename T> static constexpr int value = sizeof(T); }; template <typename T> constexpr int A::value;
3. Выравнивание.
Ошибка почти банальная, в stl специально для этого даже добавили тип std::aligned_union, но в моем старом коде такая ошибка все же была. Вот простой пример как проявляется ошибка с выравниванием, типы B, C и D должны быть одинаковыми, но из-за разного выравнивания возникает ошибка. А обнаружилась ошибка благодаря проверке передается ли в placement new выравненый указатель.
// sizeof = 8, align = 4 struct A { float f; bool b; }; // sizeof = 12, align = 4 struct B { A a; bool b; }; // sizeof = 9, align = 1 struct C { char c[ sizeof(A) ]; bool b; }; // sizeof = 12, align = 4 struct D { std::aligned_union_t<0, A> a; bool b; };
4. Move-конструктор и порядок выполнения.
В этом примере сначала вызывается move-конструктор для value, а потом считается хэш уже от невалидного value.
template <typename T> void Fuu (T &&value) { AddValue( Hash( value ), TmpObj( std::move(value) ) ); }
5. Возвращение ссылки на временный объект.
Когда-то давно наткнулся на такую ошибку. В классе Optional был метод для получения значения, потом к нему добавили еще один метод, где возвращалось либо значение из Optional класса, либо дефолтовое, передаваемое как аргумент функции. Для оптимизации все передавалось через константную ссылку, вот тут и происходит ошибка если defaultValue - создается при вызове функции, то и прибивается после выхода из функции. Valgrind как раз указал на один такой случай...
template <typename T> T const& Optional<T>::GetValue () const { return value; } template <typename T> T const& Optional<T>::GetValueOrDefault (const T& defaultValue) const { return IsDefined() ? value : defaultValue; }
6. Дефолтный дефолтный конструктор.
Использование = default для дефолтных конструкторов может привести к неинициализированным значемниям (как минимум в VisualStudio), так же есть проблемы с шаблонным конструктором с вариадиками, есть множество примеров когда такой конструктор работает не так как ожидается, поэтому конструктор с вариадиками стоит использовать осторожно.
пример на ideone
Комментариев нет:
Отправить комментарий