c++ - 返回值部分且确定性地变化

标签 c++ pointers constructor iterator

我正在实现自定义 cend返回我认为是空字母的运算符。 const_iterator 的构造函数创建了一个 const_iterator,它将指向字母 Letter 的指针作为私有(private)数据成员存储。作为参数传递。

我正在使用一个循环来检查 cons_iterator 是否不同于 cend , 因为 it永远不等于 cend .我用gdb调试了程序,发现it达到我实际存储在树中的空字母,这是预期的行为并且是正确的。我还调试了 Letter ()构造函数,它返回一个正确的空字母:

我对其他数据成员没有任何随机行为,所以我认为这一定是我的实现中的错误,但我不知道它可能是什么。

这是一个MRE:

#include <cstdio>

/*
 * LETTER'S HEADER
 */

class Letter {
private:
    char    grafema;
    bool    concluye;
    Letter* sister;
    Letter* daughter;
    Letter* mother;

public:
    Letter  ();
    Letter  (char g, bool c, Letter & m);
    Letter  (char g, bool c);

    char    Grafema  () const;
    bool    Null     () const;
    Letter* Sister   () const;
    Letter* Daughter () const;
    Letter* Mother   () const;

    void SetSister   (Letter & h);
    void SetDaughter (Letter & h);

    bool operator == (const Letter & other) const;
};

/*
 * TREELETTERS' HEADER
 */

class TreeLetters {
public:
    class const_iterator;

private:
    Letter* root;

public:
    TreeLetters  (char g, bool c);

    Letter* Raiz();

    TreeLetters::const_iterator cbegin () const;
    TreeLetters::const_iterator cend   () const;

    class const_iterator {
    private:
        const Letter* it;

    public:
        const_iterator ();
        const_iterator (Letter letter);

        bool operator == (const TreeLetters::const_iterator & other) const;

        const Letter   & operator *  ();
        const_iterator & operator ++ ();
    };
};

/*
 * LETRAS'S METHODS
 */

Letter :: Letter ()
    :grafema  ('\0'),
     concluye (false),
     sister   (nullptr),
     daughter (nullptr),
     mother   (nullptr)
{ }

Letter :: Letter (char g, bool c, Letter & m)
    :grafema  (g),
     concluye (c),
     sister   (nullptr),
     daughter (nullptr),
     mother   (&m)
{ }

Letter :: Letter (char g, bool c)
    :grafema  (g),
     concluye (c),
     sister   (nullptr),
     daughter (nullptr),
     mother   (nullptr)
{ }

void Letter :: SetSister (Letter & h) {
    if (!sister) {
        sister = &h;
    }
    else {
        Letter* aux = sister;
        sister = &h;
        h.sister = aux;
    }
}

void Letter :: SetDaughter (Letter & h) {
    if (!daughter) {
        daughter = &h;
    }
    else if (daughter->Null()) {
        Letter* aux = daughter;
        daughter = &h;
        h.daughter = aux;
    }
}

char Letter :: Grafema () const {
    return grafema;
}

bool Letter :: Null () const {
    return !grafema && !concluye && !sister && !daughter && !mother;
}

Letter* Letter :: Sister () const {
    return sister;
}

Letter* Letter :: Daughter () const {
    return daughter;
}

Letter* Letter :: Mother () const {
    return mother;
}

bool Letter :: operator == (const Letter & other) const {
    return grafema  == other.grafema
        && concluye == other.concluye
        && sister  == other.sister
        && daughter     == other.daughter
        && mother    == other.mother;
}

TreeLetters :: TreeLetters (char g, bool c) {
    root = new Letter(g, c);
}

Letter* TreeLetters :: Raiz () {
    return root;
}

TreeLetters::const_iterator TreeLetters :: cbegin () const {
    return const_iterator(*root);
}

TreeLetters::const_iterator TreeLetters :: cend () const {
    return const_iterator(Letter());
}

TreeLetters::const_iterator :: const_iterator (Letter letter)
    :it (&letter)
{ }

bool TreeLetters::const_iterator :: operator ==
                               (const TreeLetters::const_iterator & other) const {
    return *it == *other.it;
}

const Letter & TreeLetters::const_iterator :: operator * () {
    return *it;
}

TreeLetters::const_iterator & TreeLetters::const_iterator :: operator ++ () {
    if (!it->Null()) {
        if (it->Daughter()) {
            it = (it->Daughter());
        }
        else {
            while (!it->Sister() && it->Mother())
                it = (it->Mother());

            it = (it->Sister());
        }
    }

    return *this;
}

/*
 * MAIN TEST METHOD
 *
 * Creates a tree with this structure:
 *
 *          a -- null_letter
 *          |
 *          b
 *
 * This is how the tree is created with the other methods (and works well).
 */

int main () {
    TreeLetters tree('a', false);

    Letter null_letter,
          daughter('b', true, *tree.Raiz());

    tree.Raiz()->SetSister(null_letter);
    tree.Raiz()->SetDaughter(daughter);

    TreeLetters::const_iterator iter = tree.cbegin();

    while (!(iter == tree.cend())) {
        printf ("-> %s\n", "found one");
    }
}

我究竟做错了什么?我希望我没有错过任何细节。

编辑:我已将大部分名称更改为英文,因为这是一个更大的文本,可以用多种语言阅读。

最佳答案

TreeLetras::const_iterator :: const_iterator (Letra letra)
    :it (&letra)
{ }

这总是存储到 it指向构造函数本地变量的指针(参数 letra )。稍后使用该指针可能会导致未定义或未指定的行为,因为局部变量将在构造函数返回时被销毁。

您没有存储指向传递的 Letra 的指针,但参数中的拷贝。但是,即使您确实通过引用获取了参数,您仍然会存储一个指向临时对象的指针,该对象将在 return const_iterator(Letra()); 行之后被销毁。 .

尽管我不确定这是您想要的还是解决问题的最佳方法:

如果您想将迭代器存储到 Letra 的实例中表示空/结束,那么您需要确保该实例至少与迭代器本身一样长。实现此目的的一种方法是为实例提供静态存储持续时间:
TreeLetras::const_iterator TreeLetras :: cend () const {
    static Letra cend_letra;
    return const_iterator(cend_letra);
}

但构造函数必须通过引用获取参数:
TreeLetras::const_iterator :: const_iterator (const Letra& letra)

关于c++ - 返回值部分且确定性地变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59494089/

相关文章:

c++ - 是否可以创建 vector map ,其中 vector 可以是任何类型?

c++ - 简单的概念检查

c++ - 局部变量的代码块自动完成

解析时间军事时间字符串的极端情况

c++ - 我们可以说构造函数创建对象吗?

java - 在CS151(第二编程类)中,需要设置一个Object等于一个int Java

c++ - visual studio 代码不是自动完成 std​​::in c++ on ubuntu

c++ - address of operator 可以初始化一个指针但是填充的值是垃圾

C语言: How to use memset to reset dynamic 2d array?

c++ - 如果给定的模板参数提供类型定义,则使用 sfinae 启用构造函数