1

My compiler doesn't support C++11.

It turns out there's no easy way to initialize the elements of a Standard Library container. For instance, if you want to initialize a vector of strings, you'd normally use a sequence of push_back() calls like this:

// file.h 
void init_input_tbl(vector<string>& tbl){
tbl.push_back("jan");
tbl.push_back("feb");
tbl.push_back("mar");
tbl.push_back("apr");
tbl.push_back("may");
tbl.push_back("jun");
tbl.push_back("jul");
tbl.push_back("aug");
tbl.push_back("sep");
tbl.push_back("oct");
tbl.push_back("nov");
tbl.push_back("dec");}

vector<string>month_input_tb  

// file.cpp
main(){
init_input_tbl(month_input_tb);
//...

Q1. Is there another way to initialize containers in C++03?

In addition to that when I try to initialize, using function init_input_tbl() inside the header file or in the global environment it displays the following error: this declaration has no storage class or type specifier.

Q2. What method or technique there is to initialize vector month_input_tbusing init_input_tbl() inside file.h or in the global environment?

Ziezi
  • 6,375
  • 3
  • 39
  • 49
  • possible duplicate of [Default member values best practice](http://stackoverflow.com/questions/11594846/default-member-values-best-practice) – Lord Zsolt Apr 09 '15 at 11:27
  • 2
    I don't quite see how that could be a duplicate... – David Rodríguez - dribeas Apr 09 '15 at 11:31
  • 1
    Totally unrelated to your problem and your question, but why do you have that `return` statement in the `init_input_tbl` function? It doesn't serve any practical purpose, as the function will return anyway. – Some programmer dude Apr 09 '15 at 11:33
  • I don't see why you're asking "to avoid initialization in the .cpp file". Are you simply looking for a convenient way to initialize complex objects - such as a vector with many elements? – Aaron McDaid Apr 09 '15 at 11:53
  • @Aaron McDaid Yes, I'm asking for convenient way to initialize complex objects. The ".cpp file thing" appeared when I tried to initialize `vectormonth_input_tb` , using function `void init_input_tbl(vector& tbl)`, within the `file.h`, which lead to the question. – Ziezi Apr 10 '15 at 12:28
  • As for your **Q2**, you can do anything in a `.h` file that you can do in a `.cpp` file. C++ is strange like that. It would help if you clearly gave us the code that failed, instead of just saying "I try to initialize" – Aaron McDaid Apr 10 '15 at 16:13

4 Answers4

2

The alternative for a global would be to create a function that returns the value you want to use in the initialization:

std::vector<std::string> month_inputs();
std::vector<std::string> month_input_tb = month_inputs();

Then in the cpp (or the header if you make this inline) you can define the function:

std::vector<std::string> month_inputs() {
    std::vector<std::string> result;
    result.push_back(...);
    ...
    return result;
}

If you can pull in some additional dependencies you could use boost assign that provides this type of functionality already:

std::vector<std::string> month_inputs_tb = list_of<std::string>()("One")("Two");
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
2

First of all, declaring a global variable like that in a header, without static or a class to go with it, is a bad idea. If the header is included in multiple .cpp files, you're going to have compiler problems.

One solution to your problem is using a Singleton Pattern. A class with a static variable gettable by a function that gets initialized the first time the function is called.

The solution by David Rodriguez also works, but you're going to fall back on the problem of the header file that can only be included in one source file. But if you do it like that:

//utils.h

struct utils {
    static std::vector months_inputs_tb;
};
//utils.cpp
#include "utils.h"

std::vector month_inputs() {
    ...
}

utils::months_inputs_tb = month_inputs();
//code.cpp
#include "utils.h"


//use utils::months_input as you want

Then you can freely include the header containing months_inputs_tb in multiple .cpp files.

coyotte508
  • 9,175
  • 6
  • 44
  • 63
  • 1
    Good pointing out that the definition of the variable in the header will cause issues in the event of multiple translation units including the header. An alternative to making this a class static would be to change the definition in the header to be a declaration: `extern std::vector months_inputs_tb;` and provide the definition in the .cpp; but you are right that there is no solution to having it all in the header. – David Rodríguez - dribeas Apr 10 '15 at 08:51
  • @DavidRodríguez-dribeas: I'd never thought about putting extern in a header. That may actually simplify some of my existing code :) – coyotte508 Apr 10 '15 at 09:21
1

If you want to avoid any kind of initialization in your main cpp file your best option is to use compiler specific library init/constructor like DllMain in MSVC or __attribute__((constructor)) in g++. I believe there is no guarantees on an order of initializers of static class members in the c++ program scope.

E.g. g++:

#include <vector>
#include <string>
#include <iostream>

using namespace std;

__attribute__((init_priority(1000)))
vector<string> myvect;

__attribute__((constructor(1001)))
void myvectinit() {
   myvect.push_back("abc");
   myvect.push_back("def");
   myvect.push_back("ghi");
}

int main() {
   cout << myvect.size() << endl; // output: 3
   return 0;
}
W.F.
  • 13,888
  • 2
  • 34
  • 81
1

I'm assuming that your goal is simply a convenient way to initialize complex objects, such as vectors. (I don't understand why you care about the location of the code, headers versus cpp files).

With this helper:

template<size_t N, typename T>
vector<T> construct_vector(const T (&init)[N]) { 
    vector<T> tbl;
    for(size_t i=0; i<N; ++i) { 
        tbl.push_back( init[i] );
    } 
    return tbl;
}

you can construct your vector like this:

vector<string> month_input_tb = construct_vector((string[]) {"jan","feb"
         ,"mar","apr","may","jun","jul","aug","sep","oct","nov","dec"});

This works because you're just using string. A vector of more complex objects may be more difficult.

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88