saberyjs
saberyjs

Reputation: 19

c++ 11 segmentation fault (core dumped),but c++ 17 not

class all {
   public:
    template <typename T>
    all(T&& t)
        : data_ptr(new derived<T>(std::forward<T>(t))) {
    }
    all()
        : data_ptr(nullptr) {}
    all(const all& o)
        : data_ptr(o.clone()) {}
    all(const all&& o)
        : data_ptr(o.clone()) {}
    all& operator=(const all& o) {
        auto n = o.clone();
        if (data_ptr != nullptr) {
            delete data_ptr;
        }
        data_ptr = n;
        return *this;
    }

     all& operator=(all&& a)
    {
        if (data_ptr == a.data_ptr)
            return *this;

        swap(data_ptr, a.data_ptr);

        return *this;
    }
    
    ~all() {
        if (data_ptr != nullptr) {
            delete data_ptr;
        }
    }
    template <typename U>
    bool is() const {
        auto ret = dynamic_cast<derived<U>*>(data_ptr);
        return ret != nullptr;
    }

    template<typename U> U& as(){
        auto ret = dynamic_cast<derived<U>*>(data_ptr);
        if (ret==nullptr){
            throw std::runtime_error("type dynamic_cast error");
        }
        return ret->value;
    }
    template<typename U>operator U(){
        return as<U>();
    } 

   private:
    struct base {
        virtual base* clone() = 0;
        virtual ~base(){};
    };

    template <typename T>
    struct derived : public base {
        template <typename U>
        derived(U&& v)
            : value(std::forward<U>(v)) {
        }
        T value;
        base* clone() {
            return new derived<T>(value);
        }
    };

    base* data_ptr;
    base* clone() const {
        if (data_ptr == nullptr) {
            return nullptr;
        } else {
            return data_ptr->clone();
        }
    }
};

cmake compile options:

set (CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0 ")

test cases as follows:

int main(int argc, char const* argv[]) {
    all at = 12;
    cout << at.is<int>() << endl;
    cout<<at.as<int>()<<endl;
    cout<<int(at)<<endl;
    return 0;
}

c++11,17 both compile successful,but c++ 11 throw segmentation fault when run ,c++17 run successful,why? i'm so frustrated,can someone help me?

Here is Complete Reproducible Example (not minimal).

Upvotes: 2

Views: 125

Answers (1)

eerorika
eerorika

Reputation: 238401

all at = 12;

It seems that the conversion sequence is this:

  • A temporary object is constructed from the right hand expression, using the constructor all::all<int>(int&&).
  • That temporary object is used to initialise at.
  • Since the temporary all is non-const, the template constructor is a better match than all(const all&&).
  • Hence, all::all<all>(all&&) is invoked. This initialises a all::derived<all>::derived which has an all member that is initialised using all::all<all>(all&&) (because that is again, a better match than all::all(const all&&)), which invokes all::all(const all&&) which initialises all::derived<all>::derived which invokes all::all(const all&&) ... can you spot the pattern? The recursion never ends. You eventually get a stack overflow.

In C++17 at is initialised directly from the initialiser without involving a temporary object, so there is no stack overflow.

A simple fix is to add a move constructor:

all(all&& o) : data_ptr{std::exchange(o.data_ptr, nullptr)} {}

P.S. Avoid the use of bare owning pointers such as data_ptr. Use smart pointers such as std::unique_ptr instead.

Upvotes: 3

Related Questions