0

I have the following code in my project:

MainWindow.cpp

#include "date.h" 

Date date; //extern from date.h <- Error when instantinating this one

MainWindow::MainWindow(){//...}

date.cpp

#include "date.h" 
#include "consants.h" 

//..Stuff
Date::Date()
{
    //Use const int variable from "constants.h"
    year = constants::START_YEAR; //Works, START_YEAR is initialized
    Month month(m, y);
}
Month::Month(int month, int year)
{
    //Use const std::map<QString, std::pair<int,int>> from "constants.h"
    day_count = constants::MONTH_DAY_MAP_LY.at("January").second //ERROR, MONTH_DAY_MAP_LY is not initialized
}

constants.h

namespace constants {
const int START_YEAR = 2016;
const int YEAR_COUNT = 83;

const QList<QString> MONTH { "January", "February", "March",
        "April", "May", "June", "July", "August", "September", "October", "November", "December"};

const std::map<QString, std::pair<int, int>> MONTH_DAY_MAP{
    {MONTH[0], std::make_pair(0, 31)}, {MONTH[1], std::make_pair(1, 28)}, {MONTH[2], std::make_pair(2, 31)},
    {MONTH[3], std::make_pair(3, 30)}, {MONTH[4], std::make_pair(4, 31)}, {MONTH[5], std::make_pair(5, 30)},
    {MONTH[6], std::make_pair(6, 31)}, {MONTH[7], std::make_pair(7, 31)}, {MONTH[8], std::make_pair(8, 30)},
    {MONTH[9], std::make_pair(9, 31)}, {MONTH[10], std::make_pair(10, 30)}, {MONTH[11], std::make_pair(11, 31)}
};
const std::map<QString, std::pair<int, int>> MONTH_DAY_MAP_LY {
    {MONTH[0], std::make_pair(0, 31)}, {MONTH[1], std::make_pair(1, 29)}, {MONTH[2], std::make_pair(2, 31)},
    {MONTH[3], std::make_pair(3, 30)}, {MONTH[4], std::make_pair(4, 31)}, {MONTH[5], std::make_pair(5, 30)},
    {MONTH[6], std::make_pair(6, 31)}, {MONTH[7], std::make_pair(7, 31)}, {MONTH[8], std::make_pair(8, 30)},
    {MONTH[9], std::make_pair(9, 31)}, {MONTH[10], std::make_pair(10, 30)}, {MONTH[11], std::make_pair(11, 31)}
};
}

As you see I get the std::out_of_range error when trying to access MONTH_DAY_MAP_LY. After the debugging session I figured out that it happens because Date's constructor is called before any other function (even main). But I also found this page in the standard:

It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.

Since this rule applies to both Date date and objects from constants.h I don't know why linker initializes Date date and only ints from constants.h.

Chechen Itza
  • 111
  • 8
  • 2
    Read about [the *static initialization order fiasco*](http://stackoverflow.com/q/3035422/440558). Especially read the first paragraph of [the highest voted answer](http://stackoverflow.com/a/3036852/440558). – Some programmer dude Jul 24 '16 at 17:33

1 Answers1

0

MONTH_DAY_MAP_LY is std::map<QString, std::pair<int, int>>, so you should use std::map::at with QString as argument instead of element index: constants::MONTH_DAY_MAP_LY.at("January").second.

From the documentation:

T& at( const Key& key ); (1) (since C++11)

const T & at( const Key& key ) const; (2) (since C++11)

Returns a reference to the mapped value of the element with key equivalent to key. If no such element exists, an exception of type std::out_of_range is thrown.

Community
  • 1
  • 1
Leben Asa
  • 307
  • 1
  • 6
  • actually i do use QString element in my code, just wanted to show that there's no elements in `MONTH_DAY_MAP_LY` at all. sorry for confusing, will fix it. – Chechen Itza Jul 24 '16 at 17:44