Создать предупреждение об использовании конструктора копирования и присваивания - PullRequest
0 голосов
/ 11 января 2019

Есть ли способ заставить компилятор (в частности, MSVC 2017 здесь, но и другие могут быть интересны) выдавать предупреждение в местах, где используется конструктор копирования конкретного класса и оператор копирования-назначения используется (и таким способом, который может быть явно подавлен на каждом сайте вызовов, даже если он косвенный)?

Этот вопрос задает вопрос о возникновении ошибок компиляции, что теперь легко с удаленными методами C ++ 11, но я хочу, чтобы код все еще компилировался, просто выводя предупреждения.

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

Позволить компилятору временно пометить использование конструктора в качестве предупреждения, казалось отличным способом сделать это.

Я пытался добавить что-то вроде этого:

__declspec(deprecated) MyType(MyType const&) = default;

Но это не работает; по-видимому, = default выигрывает у всех других модификаторов.

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

#pragma warning(suppress:4996)

если я счастлив, что это обязательная копия. (В конце концов я планирую удалить их вместе с устаревшей версией конструктора - это просто служебная работа, чтобы отследить, с какими я еще не работал.)

К сожалению, есть некоторые случаи, которые я не могу подавить таким образом, например:

std::vector<MyType> list;
list.push_back(type);
list.emplace_back(MyType{ type });

Каждая из этих строк выдает предупреждения (первое, потому что это объявление поля внутри класса с обычным конструктором копирования), но только третья здесь может быть напрямую подавлена. Первые два выдают предупреждения внутри <vector> и, похоже, не подвержены подавлению (или отключению) предупреждений в этой строке кода.

Есть какой-то способ решить это или другой способ сделать то, что я хочу?

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Подумав об этом еще немного, сделав это иначе, возможно, было бы лучше (и проще) сделать это наоборот:

  1. Массовая замена всех MyType на WarnMyType (кроме фактического определения MyType, конечно).
  2. Добавьте WarnMyType с устаревшими конструкторами:

    struct WarnMyType : MyType
    {
        using MyType::MyType;
        __declspec(deprecated) WarnMyType(WarnMyType const& o) : MyType(o) {}
        __declspec(deprecated) WarnMyType& operator=(WarnMyType const& o)
            { MyType::operator=(static_cast<MyType const&>(o)); return *this; }
        WarnMyType(WarnMyType&&) = default;
        WarnMyType& operator=(WarnMyType&&) = default;
    };
    
  3. Постепенно изменить использование WarnMyType обратно на MyType, как они проверены.

  4. Удалить WarnMyType.
  5. Массовая замена всех оставшихся использований WarnMyType обратно на MyType (поскольку # 3 будет искать только те, где была выполнена копия).

Было бы неплохо, если бы инструменты позволяли найти использование конструктора / оператора так же легко, как и для именованного метода ...

0 голосов
/ 11 января 2019

Это выглядит не совсем элегантно, но мне удалось подавить наиболее распространенный шумный случай (векторный элемент класса в заголовочном файле), используя следующую тактику. Остальные случаи после этого были довольно хорошими и не нуждались в индивидуальном подавлении; они могут быть просто исправлены или проигнорированы.

  1. Добавление устаревших копий и конструкторов перемещения без устаревших элементов и назначение:

    __declspec(deprecated) MyType(MyType const& o) { /* actual impl */ }
    __declspec(deprecated) MyType& operator=(MyType const& o) { /* impl */ return *this; }
    MyType(MyType&&) = default;
    MyType& operator=(MyType&&) = default;
    
  2. Также добавьте недоставленный тип переадресации заполнителя:

    struct SuppressMyType : MyType
    {
        using MyType::MyType;
    #pragma warning(disable:4996)
        SuppressMyType(SuppressMyType const& o) : MyType(o) {}
        SuppressMyType& operator=(SuppressMyType const& o)
            { MyType::operator=(static_cast<MyType const&>(o)); return *this; }
        SuppressMyType(MyType const& o) : MyType(o) {}
        operator MyType() const { return *this; }
    #pragma warning(default:4996)
    };
    
  3. Изменить места, где копия должна была использовать SuppressMyType вместо MyType.

  4. Исправьте другие места, пока предупреждения не исчезнут.

  5. Заменить все SuppressMyType обратно на MyType, затем удалить код, добавленный в # 1.

Немного запутанный, но он добился цели.

...