初始化具有非默认构造函数的 std::array 项的更好方法?

Posted

技术标签:

【中文标题】初始化具有非默认构造函数的 std::array 项的更好方法?【英文标题】:Better way to initialise std::array item that has non-default constructor? 【发布时间】:2020-07-14 09:49:22 【问题描述】:

目前在初始化 basicEnemies 数组 时,我需要将 audioManager 传递给每个 basicEnemy 类的构造函数。但是,我有 20 个基本敌人,所以有没有更好的方法来初始化 MainGameScene 中的每个 basicEnemy,而不必像我这样做的方式重复将 audioManager 传递给构造函数?需要调用每个 basicEnemy 的构造函数。

MainGameScene.h
MainGameScene(AudioManager *audioManager)
std::array<BasicEnemy, 20> basicEnemies;
MainGameScene.cpp
MainGameScene::MainGameScene(AudioManager *audioManager) : basicEnemiesaudioManager, audioManager, audioManager, audioManager...


BasicEnemy.h
BasicEnemy(AudioManager *audioManager)

如果在调用 MainGameScene 构造函数之后的 ':' 部分是什么或者它被称为什么不是太多,那么我下次可以更准确地问?

【问题讨论】:

"':' 部分是什么" - 它叫做member initializer list。对于您的实际问题-您确定数组是正确的数据结构吗?你总是有 20 个敌人活着吗?也许std::vector 会更合适? 可能的选项:1) 使用 std::vector, std::array 无论如何在这里似乎很奇怪 2) 存储 std::unique_ptr&lt;BasicEnemy&gt; 而不是 3) 使 BasicEnemy 默认可构造 @Yksisarvinen 是的,总是有 20 个敌人活着,这永远不会改变,这就是选择数组的原因 根据定义,std::array 调用所有对象的默认构造函数。如果你不想要这个,那么使用 BasicEnemy 的向量怎么办?或者,您可以调整默认构造函数。 @SebastianHoffmann 1) basicEnemies 永远不会改变大小,所以数组是正确的吗? 2)您能否进一步扩展此 std::unique_ptr 以及它将如何与我当前的设置一起使用? 3)如果我在不同的场景中再次遇到这个问题,我想知道如何在没有默认构造函数的情况下做到这一点 【参考方案1】:

如果你坚持std::array&lt;BasicEnemy&gt;数据成员,你可以使用额外的间接级别和std::index_sequence

class MainGameScene 
private:
    static constexpr std::size_t n_enemies = 20;
    std::array<BasicEnemy, n_enemies> basicEnemies;

    template<std::size_t... is>
    MainGameScene(AudioManager* audioManager, std::index_sequence<is...>) :
        basicEnemies(is, audioManager)...
    

public:
    MainGameScene(AudioManager* audioManager) : 
        MainGameScene(audioManager, std::make_index_sequence<n_enemies>)
    
;

如果您可以放宽对数据成员类型的要求,以及std::shared_ptr(在堆上分配),另一个选项是std::optional(在自身内部存储一个对象):

class MainGameScene 
private:
    std::array<std::optional<BasicEnemy>, 20> basicEnemies;

public:
    MainGameScene(AudioManager* audioManager) 
        std::fill(basicEnemies.begin(), basicEnemies.end(), audioManager);
    
; 

【讨论】:

【参考方案2】:

您可以生成它们:

MainGameScene::MainGameScene(AudioManager *audioManager) 

    std::generate(basicEnemies.begin(), basicEnemies.end(), [&audioManager]() 
         return BasicEnemy(audioManager);
    

【讨论】:

假设BasicEnemy有一个默认构造函数。 此外,每个BasicEnemy 的构造函数仍在使用此策略调用(在生成之前)(尽管现在这是隐式的)。 我相信std::array 暗示容器类型或聚合初始化的默认构造函数,无论哪种方式,数组已经充满了元素;【参考方案3】:

为参数添加一个默认值,调用全局工厂函数:

 BasicEnemy(AudioManager *audioManager = getAudioManager() )

【讨论】:

以上是关于初始化具有非默认构造函数的 std::array 项的更好方法?的主要内容,如果未能解决你的问题,请参考以下文章

具有引用数据成员的类的默认构造函数?

编译器生成的默认构造函数是否会将std :: array中的指针初始化为nullptr?

std::array 默认初始化还是值初始化?

为啥显式允许默认构造函数和具有 2 个或更多(非默认)参数的构造函数?

如何使用初始化列表构造 std::array 对象? [复制]

具有非默认构造函数的 C++ 继承