c++11分段错误(核心转储),但c++17没有


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编译选项:

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

测试用例如下:

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都编译成功,但是c++11运行时抛出分段错误,c++17运行成功,为什么?我很沮丧,有人能帮我吗?

这里是完整的可复制的例子(不是最小的(。

all at = 12;

似乎转换序列是这样的:

  • 使用构造函数all::all<int>(int&&)从右侧表达式构造临时对象
  • 该临时对象用于初始化at
  • 由于临时all是非常数,因此模板构造函数比all(const all&&)更匹配
  • 因此,all::all<all>(all&&)被调用。这初始化了具有使用all::all<all>(all&&)初始化的all成员的all::derived<all>::derived(因为这再次是比all::all(const all&&)更好的匹配(,其调用了初始化all::derived<all>::derivedall::all(const all&&),其调用all::all(const all&&)。。。你能认出图案吗?递归永远不会结束。最终会出现堆栈溢出

在C++17中,at直接从初始化程序初始化,而不涉及临时对象,因此不存在堆栈溢出。

一个简单的修复方法是添加一个移动构造函数:

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

p.S.避免使用裸拥有指针,如data_ptr。请改用智能指针,如std::unique_ptr

最新更新