Оптимизирована ли Visual Studio 2013 в присутствии /OPT: ICF?

Я ожидаю, что следующая программа вернет 0 все время. Однако с Visual Studio 2013 (обновление 4) программа выходит из 1 в сборках релизов. Я не уверен, является ли это ошибкой или оптимизатор компилятора корректен и полагается на поведение определенного края. Если макрос CONST выключен, exe exe возвращает 0. Если оптимизатор действительно прав, могу ли я получить причину, по которой он может испускать код, который он делает?

#if 1
#   define CONST const
#else
#   define CONST
#endif


class TypeId {
public:
    bool operator== (TypeId const & other) const
    {
        return id == other.id;
    }

private:
    TypeId (void const * id)
        : id(id)
    {}

public:
    template <typename T>
    static TypeId Get ()
    {
        static char CONST uniqueMemLoc = 0;
        return TypeId(&uniqueMemLoc);
    }

private:
    void const * id;
};


int main(int, char **)
{
    typedef int A;
    typedef unsigned int B;

    if (TypeId::Get<A>() == TypeId::Get<B>()) {
        return 1;
    }
    return 0;
}

Ответ 1

Это не похоже на правильную оптимизацию в соответствии с стандартным разделом проекта С++ 11 14.8 [temp.fct.spec] говорит (выделение мое в будущее):

Каждая специализированная функция шаблона, созданная из шаблона , имеет его собственная копия любой статической переменной. [Пример:

template<class T> void f(T* p) {
static T s;
};
void g(int a, char* b) {
    f(&a); // calls f<int>(int*)
    f(&b); // calls f<char*>(char**)
}

Здесь f (int *) имеет статическую переменную s типа int и f (char **) имеет статическую переменную s типа char *. -end пример]

Так как ваш адрес переменной, складывающей их, влияет на наблюдаемое поведение, которое нарушает правило as-if.

T.C. указывает, что /opt:noicf предотвращает несоответствие поведения.

Мэтт Макнабб указывает, что в документации OPT (Оптимизация) содержится следующее примечание:

Потому что /OPT: ICF может привести к тому, что тот же адрес будет назначен различные функции или члены данных только для чтения (константные переменные скомпилированный с использованием /Gy ), он может сломать программу, которая зависит от уникальной адреса для функций или только для чтения данных. Для большего информацию см. в разделе /​​Gy (Включить привязку к функциональному уровню).

Это говорит о том, что это может быть преднамеренное несоответствие поведения. Ben Voigt говорит, что комментарий теперь перемещен в чат, что это действительно означает, что оптимизация может быть несоответствующей, но эти точки являются спорными.

Пользователь usr связан с Сообщение MS: Представляем '/Gw Compiler Switch и он говорит:

Обратите внимание, что оптимизация ICF применяется только для идентичных COMDAT, где их адрес не принят, и они доступны только для чтения. Если данные не принимаются по адресу, а затем уникальность адресации ICF не приведет к какой-либо заметной разнице, поэтому она действительна и соответствует стандарту.

и более поздний комментарий говорит:

Несмотря на то, что на нем есть полностью стандартная жалоба, когда в сочетании с /Gy потенциально нарушение поведения может привести.

Из того, что я могу сказать для /Gy для создания константных переменных, необходимо использовать __declspec (selectany), но это может быть более ясным в документации.

Как минимум мы видим, что /Gw не должно вводить несоответствующее поведение, но /Gy в комбинации с /Gw может.

Ответ 2

Нет, эта оптимизация не соответствует стандарту С++. Объявление uniqueMemLoc определяет уникальный объект для каждого экземпляра шаблона, и каждый объект имеет свой собственный адрес.

(Если бы вы использовали строковый литерал, это была бы другая история. Оптимизация была бы в этом случае.)