Visual Studio 2015: нет подписанного / неподписанного предупреждения о несоответствии в std :: make_unique?

Я только что нашел ошибку в своем коде, и я довольно озадачен, что это может произойти, так как это простое несоответствие со знаком и без знака, которое не должно происходить вообще, потому что я компилирую с предупреждением уровня 4, предупреждения как ошибки. Поэтому я попытался воспроизвести его, что довольно просто:

#include <memory>

class MyClass {
public:
MyClass( unsigned ) {}
};
int main()
{
MyClass* rawP = new MyClass(-1);                // issues a warning, as expected
auto uniqueP = std::make_unique<MyClass>(-1);   // NO WARNING??!

// silence the compiler
rawP;
uniqueP;

return 0;
}

Теперь я спрашиваю себя: в чем причина этого? Это ошибка в VS, или это общий недостаток std :: make_unique? Есть ли способ это исправить? (Visual Studio 2015 Community Update 3)

2

Решение

Вы видите комбинацию нескольких эффектов.

  1. Звонок в вашем main() совершенно законно, потому что make_unique
    Реализация шаблона соответствует подписанному типу данных.
  2. Реализация make_unique не генерирует предупреждение, потому что
    предупреждения обычно отключаются внутри системных заголовков.
  3. Visual Studio, похоже, не может обнаружить потенциал (но нет
    определенный) проблема преобразования знака внутри make_unique,

Более подробно:

1. Создание шаблона на самом деле является законным.

Типичная реализация std::make_unique выглядит так (сравнить
cppreference):

template <typename T, typename... Args>
inline std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

В вашем случае, как вы называете std::make_unique<MyClass>(-1)шаблон
создан для подписанный целое число. Следовательно, вы не получите предупреждение в вашем
код, потому что не происходит беззнаковое / подписанное преобразование.

2. Системные заголовки обычно отключают предупреждения.

тем не мение, вы мог по праву ожидать предупреждения от make_unique
реализация. Ведь когда new T(...) называется с вашей подписью
Параметр, преобразование со знаком / без знака все еще происходит. В качестве примера, возьмите
следующая программа:

#include <memory>

class MyClass
{
public:
MyClass(unsigned) { }
};

template <typename T, typename... Args>
inline std::unique_ptr<T> custom_make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

int main()
{
auto uniqueP = custom_make_unique<MyClass>(-1);
(void) uniqueP;
return 0;
}

Когда я собираю это с помощью GCC с -Wsign-conversionЯ получаю предупреждение

test.cpp: в экземпляре ‘std :: unique_ptr<_Tp> custom_make_unique (Args&& …) [с T = MyClass; Args = {int}] ‘:
test.cpp: 17: 48: требуется отсюда
test.cpp: 12: 63: предупреждение: преобразование в «unsigned int» из «int» может изменить знак результата [-Wsign-преобразование] return std :: unique_ptr (new T (std :: forward (args) …));

Итак, вопрос в том, почему вы не получаете это предупреждение для std::make_unique()
реализация? Ответ, по сути, заключается в том, что компилятор заставляет эти
предупреждения для его системных заголовков. Например, версия GCC <memory>
заголовок содержит прагму

#pragma GCC system_header

Как только эта прагма присутствует в заголовочном файле, компилятор больше не
сообщает о предупреждениях для всего, что внутри этого заголовка. От
Документация GCC:

Заголовочные файлы, объявляющие интерфейсы к операционной системе и среде выполнения
библиотеки часто не могут быть написаны на строго соответствующем C. Следовательно, GCC
дает код, найденный в системных заголовках специальной обработки. Все предупреждения, кроме
сгенерированные ‘#warning’(См. Диагностика), подавляются, пока GCC
обработка системного заголовка.

Смотрите также
этот ТАК пост за
больше деталей. Предположительно, аналогичный подход используется Visual Studio
компилятор (и, как вы написали в своем комментарии, заголовок временно уменьшает
уровень предупреждения).

3. Похоже, вы столкнулись с ограничением VisualStudio.

В случае VisualStudio на работе есть еще кое-что. Обратите внимание, как
GCC предупреждение выше говорит, что там может быть проблемой преобразования знака (в зависимости
на каких ценностях пользователи будут потом кормить в custom_make_unique). Кажется
что VisualStudio может только предупредить, если есть определенный проблема преобразования знака.
Смотрите следующую программу:

#include <iostream>

void f(unsigned) { }

template <typename T>
void g(T val) { f(val); } // GCC issues a warning, VS does NOT

int main()
{
f(-1); // GCC and VS issue a warning
g(-1); // no conversion warning here (g<int> instantiated)
}

Попробуйте онлайн.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]