оператор присваивания для класса, полученного из std :: exception - PullRequest
0 голосов
/ 19 октября 2019

Я извлек пользовательский класс исключений из std::runtime_error

Статический анализатор выдает мне предупреждение о том, что если я определю или удалим операцию по умолчанию (операторы копирования, операторы копирования / перемещения, деструкторы и т. Д.), ЯЯ должен определить или удалить их все.

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

Так какВ базовом классе есть закрытые члены, которые я не могу скопировать. Похоже, единственное решение состоит в том, чтобы вызвать базовый оператор присваивания непосредственно для части базового объекта, а затем скопировать оставшуюся часть *this объекта и, наконец, вернуть *this

, но до этогоделая это, я взглянул на то, что делает база operator=, и вот как это выглядит:

exception& operator=(exception const& _Other) noexcept
{
    if (this == &_Other)
    {
        return *this;
    }

    __std_exception_destroy(&_Data);
    __std_exception_copy(&_Other._Data, &_Data);
    return *this;
}
private:

    __std_exception_data _Data;
};

Теперь, зная, что вот моя реализация (с комментариями) для вызова назначения базы и копирования остальныхпроизводного объекта:

class Exception :
    public std::runtime_error
{
public:

    // ...

    Exception& operator=(const Exception& other)
    {
        if (this == &other)
        {
            return *this;
        }

        // first copy only base class data to *this
        *dynamic_cast<std::runtime_error*>(this) =
            runtime_error::operator=(
                *dynamic_cast<std::runtime_error*>(
                    const_cast<Exception*>(&other)));

        // then copy derived class data to *this
        mInfo = other.mInfo;
        mCode = other.mCode;

        // finally return complete copy
        return *this;
    }

private:
    std::error_code mCode;
    std::string mInfo;
};

Это правильный способ сделать это? Я думаю, что это похоже на проблему, но я не уверен.

РЕДАКТИРОВАТЬ

вот полный класс, для справки:

#pragma warning (disable : 4275)    // base needs to have DLL interface
    class ERROR_API Exception :
        public std::runtime_error
    {
    public:
        ~Exception() noexcept;  // cant be inlined in release build

        // default/delete
        Exception(const Exception&) = default;
        Exception(Exception&&) = delete;

        Exception& operator=(const Exception& other)
        {
            if (this == &other)
            {
                return *this;
            }

            // copy base class data to *this
            *dynamic_cast<std::runtime_error*>(this) =
                runtime_error::operator=(
                    *dynamic_cast<std::runtime_error*>(
                        const_cast<Exception*>(&other)));

            // copy derived class data to *this
            mInfo = other.mInfo;
            mCode = other.mCode;

            return *this;
        }

        Exception& operator=(Exception&&) = delete;

        /** Construct from error enum */
        template<typename Enum>
        Exception(Enum err_enum);

        /** Construct from error enum and string*/
        template<typename Enum>
        Exception(Enum err_enum, String message);

        /** Construct from error_code object */
        inline Exception(std::error_code err_code);

        /** Construct from error_code object and string */
        inline Exception(std::error_code err_code, String message);

        /** Get error_condidtion name */
        inline virtual std::string ConditionName() const;

        /** Get error_category name */
        inline virtual std::string CategoryName() const;

        /** Get error_condition value */
        inline virtual int ConditionValue() const noexcept;

        /** Get error_condition value */
        inline virtual int ErrorValue() const noexcept;

        /** Get additional information string passed to constructor */
        inline virtual const String& GetInfo() const noexcept;

        /** Get error_code object associated with this exception object */
        inline virtual const std::error_code& code() const noexcept;

    private:
        SUPPRESS(4251);     // member needs to have DLL interface
        std::error_code mCode;
        SUPPRESS(4251);     // member needs to have DLL interface
        String mInfo;
    };
#pragma warning (default : 4275)    // base needs to have DLL interface

1 Ответ

0 голосов
/ 19 октября 2019

Благодаря замечательным комментариям Ульриха Экхардта, Питера и других, вот как я сделал это, результат не является предупреждением вообще:

class Exception : public std::runtime_error
{
public:
    ~Exception() noexcept;  // can't be inlined in release build (defaulted in source)

    // default/delete
    Exception(const Exception&) noexcept = default;
    Exception(Exception&&) noexcept = default;
    Exception& operator=(const Exception&) noexcept = default;
    Exception& operator=(Exception&&) noexcept(false) = deault;

    // the rest of the code ...
};
...