解除引用这会导致分段错误

时间:2014-03-04 21:21:57

标签: c++ constructor segmentation-fault factory-method

我有以下功能

LinearScheme::LinearScheme() {
    cout << " empty constructor" << endl;
}


void LinearScheme::init(
    int tableId,
    std::string &basePath,
    std::vector<size_t> &colElemSizes,
    TupleDescMap &tupleDescMap,
    size_t defaultMaxFragmentSize,
    int numCols,
    BoundBases &bounds,
    std::vector<int> &colsPartitioned ) 
{
    // This linear scheme ignores bounds
    // it could be improved to use colsPartitioned for ordering (TODO)
    cout << "init Linear Scheme " << endl;

    *this = LinearScheme(); //SEGFAULTS HERE

    cout << "after cons here?" << endl;
    // init private fields    
    this->tableId_ = tableId;
    this->basePath_ = basePath;
    this->colElemSizes_ = colElemSizes;
    this->numCols_ = numCols;
    this->tupleDescMap_ = tupleDescMap;
    this->numFragments_ = 0;
    this->defaultMaxFragmentSize_ = defaultMaxFragmentSize;

    // fragmentSizesFilename_ init    
    fragmentSizesFilename_  = basePath_ + boost::lexical_cast <string>(tableId_)
        + "_cs";
    struct stat st;
    // open existing file if exists. Create new otherwise. 
    if (stat(fragmentSizesFilename_.c_str(), &st) == 0) // file existed
        openExisting();
    else
        createNew();
}

我在init而不是构造函数中初始化的原因是因为LinearScheme扩展了PartitionScheme(带有虚方法的超类)类,而另一个类执行了以递归方式使用构造函数的类。

我有一个QuadTree类,它执行相同的初始化,因为每个QuadTree构造函数都是递归应用的。 <{1}}类的init函数中的*this = QuadTree(bounds, maxSize)行正常工作。

但是,另一个子类(LinearScheme)QuadTree中的这一行会导致Seg错误。

为什么会出现这种情况的任何想法?

修改 也替换线:

*this = LinearScheme()

用这个:

*this = LinearScheme()

或整体删除它会消除Seg Fault ...为什么?

2 个答案:

答案 0 :(得分:5)

听起来不正确使用factory method / builder / deferred construction。对于许多这些对象创建模式函数,构造对象应该是一个静态方法,因为还没有一个要操作的实例。在其他人中,您可能会操纵已构造的实例。在任何一种情况下,如果你实际上在函数中构造类类型的对象,你应该使用new并最终返回它。

如果您正在使用helper方法来协助初始化,那么您根本不应该在方法本身内构建对象,而应该只是在帮助器中初始化它的一部分。

工厂模式示例:

LinearScheme* LinearScheme::create(...all_your_args....) {

    /* construct the thing we are building only if it 
    *  pass any arguments into him that he can handle directly if you'd like
    */
    LinearScheme *out = new LinearScheme(...);

    /* do whatever else you have to do */
    ....
    return out;
}

或您似乎想要的此类helper

/* this time let's just do 'init' on your object */
void LinearScheme::init(....args....) {
    /* possibly check if init has been done already */
    if ( this->init ) return;

    /* proceed to do your initialization stuff
     * but don't construct the 'this' instance since it should already exist
     */

    this->init = true; //so we don't init again if you don't need multiple init's
}

或者你可以考虑C ++ 11 alex提及的委托构造函数方法。

然而,这些都不是我在这里真正的问题。

它不起作用,因为你可能甚至没有有效的*this尊重。这可能是因为您的使用,或者可能是因为无法递归而无法创建。

以下是该模式的维基百科链接:http://en.wikipedia.org/wiki/Factory_method_pattern

鉴于你所说的不得不继续将十几个参数传递给父类和你的递归构造,你可以考虑的一个建议是创建一个小的配置结构,你通过引用而不是所有的离散参数传递。这样,每次添加/删除其他参数时,您都不必一直调整每个签名。

另一个想法是完全分离你的一个对象的构造,而不是知道如何,何地,何时应该构建它们并将其插入到层次结构中。很难说没有理解你将如何使用LinearSchme以及界面是什么。

答案 1 :(得分:2)

“...在另一个子类(LinearScheme)*this = LinearScheme()

“LinearScheme构造函数为空:LinearScheme::LinearScheme()

如果*这是LinearMethod的子类,则应该已经调用了LinearMethod的构造函数,并且该行无用。除了它调用赋值运算符 - 它是否正确定义?

最好依靠构建对象的内置机制。如果要避免重复代码,请使用C ++ 11 delegating constructors功能。它专门用于消除“init”方法。

虽然,“如果存在无限递归循环(例如,构造函数C1委托给另一个构造函数C2,而C2也委托给C1),则行为未定义。”

因此,您应该避免无限递归。在QuadTree中,您可以考虑在构造函数中为QuadTreeNode创建nullptr 指针