【问题标题】:Recursive Class Definition yields to invalid pointers in c++递归类定义在 C++ 中产生无效指针
【发布时间】:2020-04-19 21:55:12
【问题描述】:

我正在尝试创建一个具有递归结构的类,例如 Matrioska 娃娃,以便更清晰。 像这样 一个类包含 8 个 A 类型的子级。 我正在使用这个问题中指出的指针: Can a c++ class include itself as an member?

我为每个类实例分配一个索引值,以跟踪该类相对于父类的下降程度。

这是我的代码:

Tester.h

#pragma once

const unsigned int MAX_RECURSION = 3;

struct Tester
{

    Tester* Children[2][2][2];
    unsigned int Index;

    Tester(unsigned int index) : Index(index), Children()
    {
        std::cout << std::string(index, '-') << "(" << index << ")" << std::endl;
        if (index < MAX_RECURSION) {
            for (int x = 0; x < 2; x++) {
                for (int y = 0; y < 2; y++) {
                    for (int z = 0; z < 2; z++) {

                        this->Children[x][y][z] = &Tester(index + 1);;
                    }
                }
            }
        }

    }

    void Walk(int& tr)
    {

        if (this->Index < MAX_RECURSION) {
            for (int x = 0; x < 2; x++) {
                for (int y = 0; y < 2; y++) {
                    for (int z = 0; z < 2; z++) {
                        tr++;
                        (this->Children[x][y][z])->Walk(tr);
                    }
                }
            }

        }
    }

};

Main.cpp:

#include "Tester.h"
#include <iostream>
int main() {

    int c = 0;

    Tester t(1);
    t.Walk(c);

    return 0;
}

值 c 保存函数 Tester::Walk 运行的次数。

通过运行此代码,所有类都会正确创建,您可以在输出日志中看到:

-(1)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
--(2)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)
---(3)

索引为 3 的类确实被创建了 8*8 次,所以 64。(每次递归 8)。

但是当我尝试将Walk 向下移动tChildren 变量时,walk 函数只运行了8 次。通过调试,我后来发现只有前 8 个 Tester 类(main.cpp 中 t 类中的第一个)具有正确的索引,因为其他的具有 3435973836 的索引。我最初认为递归创建有问题,但日志显示索引正常工作(打印了 1 次、2 8 次和 3 64 次)。

是什么导致了这种行为?

【问题讨论】:

  • @user4581301 我该如何解决这个问题?

标签: c++ recursion


【解决方案1】:

您不应存储指向临时对象的指针。

他们的Lifetime 太短了。如果没有通过编译器错误直接阻止它,编译器可能会警告您。例如。 g++9.3 发出

..\src\test.cpp:18:68: error: taking address of rvalue [-fpermissive]
   18 |                         this->Children[x][y][z] = &Tester(index + 1);;
      |                                                                    ^

this->Children[x][y][z] = &Tester(index + 1);;

Tester(index + 1) 创建一个未命名的临时对象,该对象仅存在到行尾。在您有机会使用指向此对象的指针之前,它已超出范围并被销毁。

解决这个问题最直接的办法就是手动动态分配

this->Children[x][y][z] = new Tester(index + 1);

但您现在必须手动管理所有分配的Testers 的生命周期,这可能比看起来要复杂得多。

推荐的解决方案是使用智能指针来管理Testers 的生命周期。我将使用a std::unique_ptr,因为它是最简单且限制性最强的智能指针:

#include <iostream>
#include <memory> // unique_ptr, make_unique
const unsigned int MAX_RECURSION = 3;

struct Tester
{

    std::unique_ptr<Tester> Children[2][2][2]; 
        // array of Testers with scope-managed lifetime. When the array goes out of 
        // scope, all of the Testers will be automatically destroyed.
    unsigned int Index;

    Tester(unsigned int index) :  Children(), Index(index)
    {
        std::cout << std::string(index, '-') << "(" << index << ")" << std::endl;
        if (index < MAX_RECURSION) {
            for (int x = 0; x < 2; x++) {
                for (int y = 0; y < 2; y++) {
                    for (int z = 0; z < 2; z++) {

                        this->Children[x][y][z] = std::make_unique<Tester>(index + 1);
                            // makes a unique_ptr referencing a brand-new Tester
                    }
                }
            }
        }

    }

    void Walk(int& tr)
    {

        if (this->Index < MAX_RECURSION) {
            for (int x = 0; x < 2; x++) {
                for (int y = 0; y < 2; y++) {
                    for (int z = 0; z < 2; z++) {
                        tr++;
                        (this->Children[x][y][z])->Walk(tr);
                    }
                }
            }

        }
    }
};

【讨论】:

    猜你喜欢
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多