C++ CD库:michael_deque在推回自定义类型的派生类型时导致崩溃(仅在发布模式下)

C++ CD库:michael_deque在推回自定义类型的派生类型时导致崩溃(仅在发布模式下),c++,libcds,C++,Libcds,我使用的VS2012带有默认优化设置(/O2),这个问题只在发布模式下存在 我有一些代码使用了michael_deque(带有标准GC)和指向(抽象)类型T 当我试图向后推一个指向从T派生的类型的指针时,应用程序在退出michael\u deque的push\u back()函数时崩溃 这个问题似乎恰恰取决于这个特定的类型,因为在类bar中编写一个伪类foo(并在构造函数中打印一些东西以避免它被优化掉),然后将newbar()推回michael_deque不会导致崩溃 问题中的T类是: clas

我使用的VS2012带有默认优化设置(/O2),这个问题只在发布模式下存在

我有一些代码使用了
michael_deque
(带有标准GC)和指向(抽象)类型
T

当我试图向后推一个指向从
T
派生的类型的指针时,应用程序在退出
michael\u deque
push\u back()
函数时崩溃

这个问题似乎恰恰取决于这个特定的类型,因为在类
bar
中编写一个伪类
foo
(并在构造函数中打印一些东西以避免它被优化掉),然后将
newbar()
推回michael_deque不会导致崩溃

问题中的
T
类是:

class Task
{
public:
    Task() : started(false), unfinishedTasks(1), taskID(++taskIDCounter) {};
    Task(unsigned int parentID_) : started(false), unfinishedTasks(1), taskID(++taskIDCounter), parentID(parentID_)/*, taken(0)*/ {};
    virtual ~Task() = 0 {};

    virtual void execute() final
    {
        this->doActualWork();
        unfinishedTasks--;
    }

    virtual void doActualWork() = 0;
public:
    unsigned int taskID;    //ID of this task
    unsigned int parentID;  //ID of the parent of this task
    bool started;
    std::atomic<unsigned int> unfinishedTasks; //Number of child tasks that are still unfinished
    std::vector<unsigned int> dependencies; //list of IDs of all tasks that this task depends on

};
类任务
{
公众:
Task():started(false),unfinishedtask(1),taskID(++taskIDCounter){};
任务(未签名的int-parentID_u3;):已启动(false),未完成任务(1),任务ID(++taskIDCounter),parentID(parentID_3;)/*,执行(0)*/{};
virtual~Task()=0{};
虚拟void execute()final
{
这->实际工作();
未完成的任务--;
}
虚空doActualWork()=0;
公众:
unsigned int taskID;//此任务的ID
unsigned int parentID;//此任务的父级ID
布尔开始;
std::atomic unfinishedTasks;//尚未完成的子任务数
std::vector dependencies;//此任务所依赖的所有任务的ID列表
};
这个错误可以在一个最小的程序中重现(如果您碰巧有一个环境可以像我一样执行这个错误,只需在Task类可以看到它的地方放置一个
std::atomic taskIDCounter
):

#包括
#包括“task.hpp”
a类:公共任务
{
()
{

std::cout它确实是一个编译器错误。更具体地说,它是一个与VisualStudio2012的原子实现相关的错误

libcds库使用了std::atomic类的某些模板专门化,当在函数范围外运行时,产生的错误帧指针有时会导致非法内存访问(未定义的行为似乎可以防止调试模式下的灾难性故障)

这种特殊情况下的修复方法是使libcd使用不同的原子库,而不是Visual Studio提供的标准原子库。该库决定在cxx11_atomic.h中使用哪个实现:

#if defined(CDS_USE_BOOST_ATOMIC)
#   error "Boost.atomic is not supported"
//#   include <boost/version.hpp>
//#   if BOOST_VERSION >= 105300
//#       include <boost/atomic.hpp>
//#       define CDS_ATOMIC boost
//#       define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
//#       define CDS_CXX11_ATOMIC_END_NAMESPACE }
//#   else
//#       error "Boost version 1.53 or above is needed for boost.atomic"
//#   endif

#elif CDS_CXX11_ATOMIC_SUPPORT == 1
    // Compiler supports C++11 atomic (conditionally defined in cds/details/defs.h)
#   include <cds/compiler/cxx11_atomic_prepatches.h>
#   include <atomic>
#   define CDS_ATOMIC std
#   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
#   define CDS_CXX11_ATOMIC_END_NAMESPACE }
#   include <cds/compiler/cxx11_atomic_patches.h>
#else
#   include <cds/compiler/cxx11_atomic.h>
#   define CDS_ATOMIC cds::cxx11_atomics
#   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomics {
#   define CDS_CXX11_ATOMIC_END_NAMESPACE }}
#endif

这将导致库始终使用自己的原子实现。

您不能在VS中调试它吗?错误不会在调试模式下发生。在发布模式下,调试非常困难(即使激活了调试符号),因为该函数中的大部分内容都已优化。不幸的是,当我们取消引用悬空指针时,可能会发生崩溃。但我认为这不是由push_back引起的。是的。当程序崩溃后我停止程序时,应用程序当前正在退出push_back函数(可能在超出范围后解构某些内容)。但是,它没有显示它正在做什么。您正在本地范围中创建
任务
容器,其中包含一对额外的大括号
{}
。可能是
cds:Terminate()
正在尝试释放一些已经被释放的东西。哦,哈哈哈。时机很好。我刚刚完成了对linux的分析:/+1这是一个痛苦的错误。作为记录,该错误已针对VS2013(!)报告,因此只能通过VS2013 RTM修复
#if defined(CDS_USE_BOOST_ATOMIC)
#   error "Boost.atomic is not supported"
//#   include <boost/version.hpp>
//#   if BOOST_VERSION >= 105300
//#       include <boost/atomic.hpp>
//#       define CDS_ATOMIC boost
//#       define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
//#       define CDS_CXX11_ATOMIC_END_NAMESPACE }
//#   else
//#       error "Boost version 1.53 or above is needed for boost.atomic"
//#   endif

#elif CDS_CXX11_ATOMIC_SUPPORT == 1
    // Compiler supports C++11 atomic (conditionally defined in cds/details/defs.h)
#   include <cds/compiler/cxx11_atomic_prepatches.h>
#   include <atomic>
#   define CDS_ATOMIC std
#   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
#   define CDS_CXX11_ATOMIC_END_NAMESPACE }
#   include <cds/compiler/cxx11_atomic_patches.h>
#else
#   include <cds/compiler/cxx11_atomic.h>
#   define CDS_ATOMIC cds::cxx11_atomics
#   define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomics {
#   define CDS_CXX11_ATOMIC_END_NAMESPACE }}
#endif
#elif CDS_CXX11_ATOMIC_SUPPORT == 255