简体   繁体   中英

assignment operator for class derived from std::exception

I derived a custom exception class from std::runtime_error

static analyzer is giving me a warning that if I define or delete default operation (copy ctors, copy/move operators, destructors etc..), I should define or delete them all.

to resolve this silly warning, I wrote the missing assignment operator but then I got another warning that now my operator hides the base non virtual assignment operator!

Since base class has private members which I cant copy it looks like the only solution is to invoke base asignment operator directly for base object part and the copy the rest of *this object and finaly return *this

but before doing that I took a look on what the base operator= does and here what it looks like:

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;
};

Now knowing that Here is my implementation (with comments) to invoke base asignment and the copy the rest of the derived object:

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;
};

Is this correct way to do this? I think this looks like trouble but I'm not sure.

EDIT

here is complete class, for reference:

#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

Thanks to great comments from Ulrich Eckhardt, Peter and others here is how I made it work, result is no warning at all:

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 ...
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM