4

I'm working on some code in which a variable of type std::vector<double> is declared, before the value is specified. I can't define the value together with declaration, because it takes many lines of code to set the value. The thing is that this variable is a constant in essence, meaning it shouldn't be modified once it's set. However, it can't be declared const.

One way is to create another variable which is const and copy the value into it. const std::vector<double> a(b); would do, and use a instead of b in the program. However, my variable can be large and I wish to learn a way other than having to perform copying.

Any suggestions from you guys?

Deadlock
  • 4,211
  • 1
  • 20
  • 25
yu quan
  • 161
  • 1
  • 1
  • 14

5 Answers5

8

You may create a function to initialize it. In worst, you have a move. at best you have (N)RVO (return value optimization).

std::vector<Object> CreateBigVector();

And then

const std::vector<Object> myObject = CreateBigVector();
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • in c++11 you can use lambda to initialize const variable with complex computation: `const int immutable = []() { int mutable; ... return mutable; }();` – Martin Stangel Aug 21 '15 at 08:40
2

One way is to create a function

std::vector<Object> CreateYourVector();

and use it to initialise

const std::vector<Object> vec = CreateYourVector();

Another (technically a variation) is to create a helper class that contains your vector, and do all the work in a constructor

class Helper
{
     std::vector<Object> vec;

     public:

         Helper()
         {
               // initialise your vector here
         };

         const std::vector<Object> &TheVec() const {return vec;};
};

const Helper helper;

The above techniques can be combined, for example change the constructor

Helper() : vec(CreateYourVector()) {};

These techniques can also be mixed with others, such as the singleton pattern.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • Is the first approach invalid if it's a class member variable? What if you want to initialize the vector just once, and do it from e.g. the constructor? Do you have to have a getter function? – Andrew Jan 26 '21 at 04:16
  • 1
    @Andrew - The approach is valid if the vector being initialised is a non-static class member. The primary job of a constructor is to initialise non-static members - doing it with a getter function is optional. In the constructor it is better to use an intialiser list - this is essential for `const` members of the class, as they must be initialised on construction rather than initialised and then reassigned. The constructor (whether it does initialisation in the initialiser list or not) can call any function (including a member function of an existing object) to do the work. – Peter Jan 26 '21 at 04:34
  • Okay so I can define a `const std::vector` as a member variable, and then anywhere in or from the class's constructor assign an initializer list to it. – Andrew Jan 26 '21 at 05:18
  • 1
    @Andrew - No. non-static `const` members of a class must be initialised in the initialiser list of a constructor. (If they are not, then they will be default-initialised, or - if there is no default initialisation - there will be a diagnosable error). They cannot be reassigned after that - for example, in the body of the constructor. non-`const` members can be assigned in the constructor body, but they are still initialised (e.g. in the constructor initialiser list) before that. – Peter Jan 26 '21 at 10:07
1

I think the problem is about scoping. You have to separate your problem into two different scopes:

  • a scope where you build up your vector
  • a (or others) scope(s) where you use it

In the scope where you build up your vector, it logically isn't a const variable. Once you have built it, you want it not to be changed anymore. So you may want to refer to it through a const &.

I'd go this way:

  • define a function std::vector<double> build_up()
  • inside build_up, you define a non-const vector and you can build it
  • when you're done, you can return it by value (RVO will avoid any copy)
  • refer to the object returned by build_up() as a const object

I.e.

const std::vector<double> v = build_up();
Paolo M
  • 12,403
  • 6
  • 52
  • 73
  • I think you should also mention the inline function which can be used in header files. – cqdjyy01234 Aug 21 '15 at 07:53
  • Thanks! Lecturers will tell you that a function return by value will cause a copy action. Good to know that modern compilers perform "RVO". – yu quan Aug 21 '15 at 08:04
  • 1
    Avoid to return const object: see [should-i-still-return-const-objects-in-c11](http://stackoverflow.com/questions/13099942/should-i-still-return-const-objects-in-c11) – Jarod42 Aug 21 '15 at 08:07
  • @Jarod42 Thank you! I had just figured out that there was something odd while reading other answers. – Paolo M Aug 21 '15 at 08:14
  • just to ask, in g++ stdc++11, is "RVO" set by default? – yu quan Aug 21 '15 at 08:27
  • @user5250767 is turned on at optimization level 2 (-O2 or -O3 options) or with -felide-constructors. https://gcc.gnu.org/ml/gcc/2002-04/msg01539.html – Paolo M Aug 21 '15 at 08:40
0

In c++11, you can use the initial list to define a const vector. I think it is a easiest way. Try it: const vector<double> = {1.0, 2.0, 3.0};. It will not take many lines of code to set the value. I hope this can help you.

cwfighter
  • 502
  • 1
  • 5
  • 20
  • i know but in my case to set the values involves reading text files and conditional on those texts. Life's not always that easy :D – yu quan Aug 21 '15 at 08:33
0

The traditional approach would be to only expose a handle that enforces constness and avoids making expensive copies outside the context where the vector is created and initialized. Such handle would be a const pointer or reference.

Since you are using std::vector you can benefit from modern c++ facilities, since std::vector supports features like move semantics off-the-shelf.

In particular, I suggest you to budget some time to have a look at:

  • move semantics
  • smart pointers

which upgrade the traditional way of passing around raw pointers. They enforce ownership semantics (which context owns the object) and allow you to express your intentions in a very precise way through the code.

Emerald Weapon
  • 2,392
  • 18
  • 29