我正在实现自定义 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/