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

时间:2016-08-25 14:49:40

标签: c++ vector global-variables

以下是我的代码......

的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的构造函数,根据cards成员变量调整此类中的向量card_amount。从gdb开始,这个向量可以正确初始化,它包含10个元素。

在调用main()函数之前发生了奇怪的事情,向量被重置。在gdb中,向量的大小回滚到0,当然,后续操作(例如下标此向量)会导致段错误。

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

1 个答案:

答案 0 :(得分:0)

看起来你已经点击了static initialization order fiascoPCI_card card;之前std::vector<card_dev_t> PCI_card::cards初始化可能会发生。如果发生这种情况(并且标准允许),那么PCI_card::enlarge_vector()将在尚未初始化的向量上调用resize(此处输入UB)。执行后,PCI_card::cards的正常静态初始化将被执行 - 将向量初始化为空的初始化。这就是你看到这种行为的原因:

  

在gdb中,向量的大小回滚到0,

这是未定义的行为,因此您在gdb中看到的任何内容都是可能的。

解决方法是使卡片非静态,或者使用带静态字段的静态函数将其返回:

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

这将确保在cards

首次使用时初始化getCards.