【问题标题】:Segmentation fault in list of objects对象列表中的分段错误
【发布时间】:2015-06-09 07:18:43
【问题描述】:

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

在 Observer-controller-thread (ActiveObject) 的初始化例程中,我创建了一个 ConcreteObservers 的向量(用于通知他们离散的工作),如下所示:

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

到目前为止,我在课堂上只使用了标准的 POD 类型,所以标准的复制构造函数没有产生任何问题。 但是今天我用 std::complex 类型的向量扩展了 ConcreteObserver 类。我认为向量已经具有类型内复制构造函数的能力,但我得到的只是一个分段错误,就在创建 ConcreteObserver 之后。那么为什么这不起作用呢?

编辑: 线程 Resynthesis 是一个 ACE::ActiveObject(线程)并维护观察者。该线程有一个 Subject mEventMonitor 作为成员变量,它控制所有具体的观察者(ConcreteResynthesis),它们被创建并存储在 init- 中的 std::vector 中。 再合成的例程(如上图)。一旦要执行的工作通过 TCP 来自另一个程序,Resynthesis 会在 Subject 注册所需数量的具体观察者,并分别“通知”他们要做的工作。

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

中是空的

在定义工作区域后的重新合成中,我这样通知具体观察者:

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

问题是观察者在 Resynthesis 的初始化例程中创建一次,所以在我找到工作之前,只有 ConcreteResynthesis 的构造函数被调用。但是使用类中的向量,我在创建第一个具体观察者后出现分段错误

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

赋值运算符(复制构造函数几乎相同,但 wothpout 返回 this 指针且不带 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;
}

【问题讨论】:

  • 感谢提及,改成c++
  • 你去 - 现在你有语法突出显示!
  • 默认的复制ctor应该可以复制一个向量。您应该尝试构建一个 MVCE。
  • 如果你的意思是 MVC,那么我必须说我使用的是 Linux,带有一个标准的控制台项目
  • @mbed_dev 你给了我们一行代码,其中包含我们不知道的变量。我们如何用如此少的信息帮助您解决这个问题?我们唯一能告诉您的是您的程序有错误。

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


【解决方案1】:

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

根据您的描述,由于您使用了std::vector&lt;ConcreteResynthesis&gt;,您确实在实例之间共享指针。您还提到,在完成所有操作后,您将手动释放线程管理器中的指针。这似乎是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 也可以毫无问题地复制。

【讨论】:

    猜你喜欢
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    • 2016-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-19
    • 2021-06-12
    相关资源
    最近更新 更多