在调用main()函数之前重置全局对象中的向量

vector in global object is reset before main() function invoked

本文关键字:全局 对象 向量 main 调用 函数      更新时间:2023-10-16

以下是我的代码…

main.cpp

/* header files are included here */
PCI_card card;
int main(void)
{
    card.init_card(0);
    return 0;
}

pci_card.h

#ifndef __PCI_CARD_H
#define __PCI_CARD_H
/* header files are included here */
typedef struct {
    int32_t card_index;
    int32_t user_counter;
} card_dev_t;
class PCI_card {
public:
    PCI_card() : dev_descriptor(-1) { enlarge_vector(); }
    int32_t init_card(int32_t card_num);
private:
    int32_t dev_descriptor;
public:
    static int32_t enlarge_vector();
private:
    static int32_t card_amount;
    static std::vector<card_dev_t> cards;
};
#endif

pci_card.cpp

/* header files are included here */
int32_t PCI_card::card_amount = -1;
std::vector<card_dev_t> PCI_card::cards;
int32_t PCI_card::init_card(int32_t card_num)
{
    if (card_num >= card_amount || card_num < 0)
        return -1;
    card_dev_t new_card = {
        .card_index = card_num,
        .user_counter = 1
    };
    cards[card_num] = new_card;
    dev_descriptor = card_num;
    return 0;
}
int32_t PCI_card::enlarge_vector()
{
    card_amount = 10;
    card_dev_t null_card = {
        .card_index = -1,
        .user_counter = -1
    };
    cards.resize(card_amount, null_card);
    return card_amount;
}

main.cpp中,card被定义为全局变量,当然,在调用main()函数之前应该对其进行初始化,这可以通过gdb清楚地看到。

初始化card时,调用PCI_card类的构造函数,根据card_amount成员变量调整该类中的向量cards的大小。从gdb中,这个向量被正确初始化,它包含10个元素。

在调用main()函数之前发生了奇怪的事情,向量被重置。在gdb中,vector的大小回滚到0,当然,后续的操作,比如下标这个vector,会导致segment fault error。

我不知道这里发生了什么....这太荒谬了……

看起来您遇到了静态初始化顺序惨败。PCI_card card;的初始化有可能发生在std::vector<card_dev_t> PCI_card::cards之前。如果发生这种情况(并且标准允许),那么PCI_card::enlarge_vector()将调用resize(这里输入UB)尚未初始化的向量。执行完PCI_card::cards后,将执行正常的静态初始化——将vector初始化为空vector。这就是为什么你会看到这样的行为:

在gdb中,vector的大小回滚到0,

这是未定义行为,所以你在gdb中看到的任何东西都是可能的。

解决方案是将卡片设置为非静态的,或者使用带有静态字段的静态函数返回卡片:

std::vector<card_dev_t>& getCards() {
   static std::vector<card_dev_t> cards;
   return cards;
}

这将确保cards在第一次使用getCards.时被初始化