Reputation: 19
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
Reputation: 238401
all at = 12;
It seems that the conversion sequence is this:
all::all<int>(int&&)
.at
.all
is non-const, the template constructor is a better match than all(const all&&)
.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