对象列表中的分段错误

时间:2015-06-09 07:18:44

标签: c++ design-patterns vector segmentation-fault copy-constructor

我没想到会这么难,但我有以下程序: 在多线程环境中(使用ACE-Framework和OpenMP),我使用Observer模式。

在Observer-controller-thread(ActiveObject)的init-routine中,我创建了一个 ConcreteObservers 的向量(用于通过离散的作业通知它们),如下所示:

mResynthesisVec.assign(cMaxEDTDetection, ConcreteResynthesis(pClientObj));

到目前为止,我在类中只使用了标准的POD-Types,因此标准的copy-constructor没有出现任何问题。 但今天我用一个std :: complex-type的向量扩展了ConcreteObserver类。我认为向量已经具有in-type copy-constructor功能,但在创建ConcreteObserver之后,我得到的只是一个分段错误。那么为什么不起作用呢?

修改 线程 Resynthesis 是一个ACE :: ActiveObject(Thread)并维护观察者。该线程有一个Subject mEventMonitor 作为成员变量,它控制所有具体观察者( ConcreteResynthesis ),它们在init中的std :: vector中创建并存储。 再合成的常规(如上所示)。一旦要执行的作业来自TCP上的另一个程序, Resynthesis 就会在主题上注册所需数量的具体观察者,并且通知"分别给他们做的工作。

typedef std::complex<float> TComplexType;
typedef std::vector<TComplexType> TFFTContainer;
typedef TFFTContainer::iterator TFFTContIter;
typedef std::vector<float> TWindowContainer;

class ConcreteResynthesis: public Subject::Observer {

public:
    ConcreteResynthesis();
    ConcreteResynthesis(TCPClient * client);
    virtual ~ConcreteResynthesis();
    virtual void Notify(TBinPos value, int workSignal, int shotCntr, int     shots);    /// Function called by observed Subject
... some methods
        private:
    TBinPos mPos;   ///< Last observed value
    TCPClient * pClientObj;
    TFFTContainer mFFTDataCont;    //makes the problem
    fftwf_plan mFFTWPlan;
    unsigned int mCurrentLength;
    unsigned int mSignalPos;
    TFFTContainer tFullSignal;   //makes the problem

        };

ConcreteResynthesis 的构造函数如下所示

ConcreteResynthesis::ConcreteResynthesis(TCPClient *client) : ///<avaroa(0),
        pClientObj(client) {

    fftwf_init_threads();   ///< does only need to be called once, so do it here

}

虚拟析构函数在 ConcreteResynthesis

中为空

在定义工作区域后的 Resynthesis 中,我通知conrete-observers它是这样的:

for (int i = 0; i < iSignalCntr; ++i)
    mEventMonitor.ConcreteNotify(pClientObj->GetBinPositions(i), i, sBurstCounter, sBursts);

问题是观察者在 Resynthesis 的init例程中创建了一次,所以直到我得到一个工作,只调用 ConcreteResynthesis 的构造函数。但是对于类中的向量,我在创建第一个具体观察者

之后得到了分段错误

EDIT2 正如我所建议的那样,我实现了复制构造函数,析构函数和赋值运算符。但我仍然得到segmenattoin错误。在析构函数中,我将指针设置为零,因为删除是另一个负责的线程。下面你可以看到3&#39;的规则。实现:

赋值运算符(对于复制构造函数几乎相同,但是wothpout返回this-pointer而没有if语句)

ConcreteResynthesis & ConcreteResynthesis::operator=(const ConcreteResynthesis & rhs) {
    if (this != &rhs) {
        mRange = rhs.mRange;
        pClientObj = rhs.pClientObj;
        pDataPool = rhs.pDataPool;
        tFullSignal = rhs.tFullSignal;
        mPos = rhs.mPos;    ///< Last observed value
        mFFTDataCont = rhs.mFFTDataCont;
        mZeroBytes2Add = rhs.mZeroBytes2Add;
        mNextPowOf2 = rhs.mNextPowOf2;
        //mFile = rhs.mFile;
        mFFTWPlan = rhs.mFFTWPlan;
        mFFTW_WisdomString = 0;
        //mutable ACE_Thread_Mutex mMutex;  ///< A mutex to guard the value
        mCurrentLength = rhs.mCurrentLength;
        mSignalPos = rhs.mSignalPos;
    }

    return *this;
}

虚拟析构函数:

ConcreteResynthesis::~ConcreteResynthesis() {

    pClientObj = 0;
    pDataPool = 0;
}

1 个答案:

答案 0 :(得分:0)

这可能无法解决您的所有问题,但您应该做的一件事就是将TCPClient指针作为std::shared_ptr而不是原始指针。

根据您的描述,由于您使用std::vector<ConcreteResynthesis>,您确实在实例之间共享指针。您还提到在完成所有操作后,您将在线程管理器中手动取消分配指针。这似乎是std::shared_ptr的一个用例。

您的ConcreteResynthesis班级有以下成员:

TBinPos mPos;   ///< Last observed value
TCPClient* pClientObj;
TFFTContainer mFFTDataCont;    //makes the problem
fftwf_plan mFFTWPlan;
unsigned int mCurrentLength;
unsigned int mSignalPos;
TFFTContainer tFullSignal;   //makes the problem

改为:

#include <memory>
//...
TBinPos mPos;   ///< Last observed value
std::shared_ptr<TCPClient> pClientObj;
TFFTContainer mFFTDataCont;    //makes the problem
fftwf_plan mFFTWPlan;
unsigned int mCurrentLength;
unsigned int mSignalPos;
TFFTContainer tFullSignal;   //makes the problem

当调用ConcreteResynthesis个对象的实例副本时,共享指针将提升引用计数。向量中的每个对象将使用相同的单个指针。当销毁使用共享指针的最后一个实体时(破坏使引用计数为0),最后删除指针。

随着std::vector内部的所有复制和破坏,std::shared_ptr成员负责所有的工作,你的析构函数(现在不再需要)试图用一个不优雅的工作做方式(将指针设置为0,在一种“穷人的移动构造函数”类型的时尚)。

除此之外,您不需要用户定义的复制构造函数,赋值运算符或析构函数,使代码更清晰,更不容易出错。

请注意,通过所有这些,我假设基类Subject::Observer也可以复制而没有问题。