Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing C++ const fields after the constructor

I want to create an immutable data structure which, say, can be initialized from a file.

class Image {
public:
   const int width,height;
   Image(const char *filename) {
     MetaData md((readDataFromFile(filename)));
     width = md.width();   // Error! width  is const
     height = md.height(); // Error! height is const
   }
};

What I could do to fix the problem is

class Image {
   MetaData md;
public:
   const int width,height;
   Image(const char *filename):
     md(readDataFromFile(filename)),
     width(md.width()),height(md.height()) {}
};

However

  1. It forces me to save MetaData as a field in my object. Which I don't always want.
  2. Sometimes the logic in the constructor is much more complex than a single read (say, error handling can take a few lines)

So the only solution I thought of is along the lines of

class A {
  int stub;
  int init(){/* constructor logic goes here */}
  A():stub(init)/*now initialize all the const fields you wish
  after the constructor ran */{}
};

Is there a better idea? (In Java, you're allowed initializing finals in the constructor).

like image 800
Elazar Leibovich Avatar asked Aug 12 '10 06:08

Elazar Leibovich


1 Answers

You could move width and height into one type and move the initialization code into an initialization helper function:

// header:
struct Size { 
    int width, height;
    Size(int w, int h) : width(w), height(h) {}
};

class Image {
    const Size size; // public data members are usually discouraged
public:
    Image(const char *filename);
};

// implementation:
namespace {
    Size init_helper(const char* filename) {
        MetaData md((readDataFromFile(filename)));
        return Size(md.width(), md.height());
    }
}

Image::Image(const char* filename) : size(init_helper(filename)) {}
like image 65
Georg Fritzsche Avatar answered Oct 06 '22 05:10

Georg Fritzsche