2

I would like to carry out a lazy initialization of a set of (std::vector) attributes in c++. They have to be const, in the sense that after the first time they are initialized (via a get method), their values cannot be modified. What is the cleanest way to do this?

I tried to define the attributes as const, but in this way they must be initialized in the construntor initialization list, so no lay initialization seems to be possible.

3
  • Via a constexpr std::vector + immediately invoked (constexpr) lambda. Assuming you know /can calcluate everything at compile time. Otherwise you can use a "meyer's singleton approach" const std::vector<int>& getConstVector() { static std::vector<int> values = immediate_invoked_lambda[]{ ... initialization code here ... }(); return values; } Commented Jan 18 at 15:03
  • 1
    You don't want const, you want logically constant. Then implement a lazy<T> for your lazily initialized set of attributes. Make the lazy<T> have a logically constant interface, rather than be a const object itself. Commented Jan 18 at 15:10
  • While a const vector cannot be modified in size it's contents can be since they cannot be const. see this Commented Jan 18 at 16:28

3 Answers 3

3

You might do something like:

class MyClass
{
public:
    const std::vector<int>& getV()
    {
        if (!v) {
            v = std::vector{4, 8, 15, 16, 23, 42};
        }
        return *v;
    }
private:
    std::optional<std::vector<int>> v;
};

If some specific value is "prohibited" from vector (as empty vector), you might remove optional and use that value instead.

Sign up to request clarification or add additional context in comments.

Comments

1

You may use the "Meyer's singleton" pattern by using a static in the getter itself. This give the guaranty to be initialized on first access (and is even thread safe)

struct MyClass
{
    const std::vector<int>& getV()
    {
       static auto v = std::vector{4, 8, 15, 16, 23, 42};
    
       return v;
    }
};

full working example there => https://godbolt.org/z/8jheTq1WT

1 Comment

You don't even need the class.
-1

Proper handling of Lazy initialization needs language support that is currently unavailable in C++. But using the return value of functions is a possibility. Therefore, we can use the IILE(immediately invoked lambda expression) pattern:

auto const my_lazy_vec = 
[& /*capture all by ref*/ ]{
    std::vector<elements> nrvo;
    {// safety scope for nrvo
        if (case_1)
           do_fill(nrvo, value_set_1);
        else if (case_2)
           do_fill(nrvo, value_set_2);
        else if (case_3)
           do_fill(nrvo, value_set_3);
        return nrvo;
    };//safety scope for nrvo
}(/*IILE*/);// init my_lazy_vec

In the above snippet nrvo is not essential, but serves as a good example. Using lambda, makes the initialization logic local and visible - while still conditional and flexible. And the result of immediate evaluation is directly initialized into a const object. In other words, the mutable stage of object's lifetime is handled inside the lambda, while the immutable part is handled by the return value.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.