I'm trying to create a static const
list of default objects (Rules) that are to big to be frequently copied and as such I want to store them in a vector
of unique_ptr<>
. I've noticed that similar questions has made the rounds a few times but I'm unclear as to whether this is actually doable (I'm leaning towards not doable). I.e.
initializer_list
with unique_ptr
since access to the members are const resulting in a copy operation.Thus both:
static const std::vector<std::unique_ptr<std::string>> kStrings = {
std::unique_ptr<std::string>(new std::string("String 1")),
std::unique_ptr<std::string>(new std::string("String 1"))
};
and
static const std::vector<std::unique_ptr<std::string>> kStrings(
std::unique_ptr<std::string>(new std::string("String 1")),
std::unique_ptr<std::string>(new std::string("String 1"))
);
are not feasible.
Am I misunderstanding? Is there another way to initialize such a vector or is this a case of rethinking the design? The simplest alternative I can think of is to create the objects a static const
and then referencing those as raw pointers. For example:
static const std::string kString1 = "String 1";
static const std::string kString2 = "String 2";
static const std::vector<const std::string*> kStrings = {&kString1, &kString2};
It feels nasty, but the code interfaces remains relatively unchanged and since it does not leave the scope of the class it is also transparent to the users.
Any thoughts, corrections or better alternatives is appreciated.
EDIT - Regarding this question, I've tested the solution and it also works. My problem with the solution is it enables initializer_list
to used in a way they were not designed to be used and I don't know what unintended consequence that will have, if any.
Am I misunderstanding? Is there another way to initialize such a vector
There is, call a function that returns a non-const vector to use as an initializer. It doesn't even have to be named. It could be an immediately invoked lambda.
static const std::vector<std::unique_ptr<std::string>> kStrings = [] {
std::vector<std::unique_ptr<std::string>> ret;
// populate ret
return ret;
}(); // <-- Invoke the lambda immediately after defining it.
Now you can have your complex initialization logic and treat kStrings
as const still. Furthermore, it's quite likely compilers will inline the lambda entirely, so there isn't even going to be the overhead of a function call. It really is having your cake and eating it too.
Though one has to wonder why you'd use a vector of unique pointers to strings (a value type). A vector already owns its content. So you could possibly cut the middleman, and that will simplify initialization as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With