0

Previously asked questions (1 and 2) on SO seem to suggest that applying std::move on elements of a std::initializer_list may lead to UB. In fact, std::initializer_list iterators prevent effective move because they refer to const elements. The reason is that compilers may use static read-only memory for storing the underlying array of an initializer_list.

I think this view is too limiting and I wanna know if experts out here agree. IMO, the following code cannot possibly use the read-only store.

void attempt_move(std::initializer_list<std::string> list) {
  // must use const std::string &. Can't move.
}
int main(int argc, char *argv[])
{
  if(argc >= 4)  
    attempt_move({ argv[1], argv[2], argv[3] }); 
}

The underlying std::string array cannot possibly live in a read-only store because, AFAIK, read-only store must be initialized before main and the argv parameters are not known at that time. In fact, the C++11 standard says: "[ Note: The implementation is free to allocate the array in read-only memory if an explicit array with the same initializer could be so allocated. —end note ]". Seems like this is one case where the "explicit array with the same initializer" cannot be allocated read-only. So it probably has automatic storage.

If that's true, seems like there are lost opportunities to move the string objects due to const iterators of std::initializer_list. Is there a workaround?

Community
  • 1
  • 1
Sumant
  • 4,286
  • 1
  • 23
  • 31
  • FYI. cpptruths has a new blog post on this: http://cpptruths.blogspot.com.au/2013/09/21-ways-of-passing-parameters-plus-one.html – goji Sep 17 '13 at 07:21

1 Answers1

0

You can const_cast away qualification if the underlying object isn't const-qualified, but only the reference is.

But const qualification isn't necessarily the same thing as being stored statically in physical ROM. In most cases, the compiler simply believes it's safe that the object won't be modified by anyone.

Yes, it's undefined behavior. And this is considered a serious shortcoming of initializer_list. Hopefully it will be fixed for C++17.

Yes, you'll probably get away with it if moving is the only thing that ever happens to those elements, which in fact covers almost all the safe use-cases of initializer_list under the sun.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Don't forget that it is possible to move `const &&`, if you provide the move constructor. – user1095108 Sep 16 '13 at 06:24
  • @user1095108 And what's that constructor supposed to do? – Potatoswatter Sep 16 '13 at 06:25
  • Well, `&&` is just another kind of reference, you can copy from it, cast, even though that also causes UB. – user1095108 Sep 16 '13 at 06:29
  • @user1095108 Assuming you don't do UB, you can only copy from it. So `const &&` is just the same as `const &` except it doesn't accept lvalues. Actually there is a use, for artificial move semantics where the given object is a proxy and moving it actually moves another resource through writable reference, or perhaps something with a `mutable` member. But that's all generally inadvisable. (I tried it once and it did not end well.) – Potatoswatter Sep 16 '13 at 06:37
  • What I don't understand is what problem moving an object from a `ROM` could possibly cause. So, it is in `ROM`, but the object you move to is in the stack, big deal? – user1095108 Sep 16 '13 at 07:03
  • 3
    @user1095108 The idea isn't problematic, it's meaningless. By definition all you can do from ROM is copy. – Potatoswatter Sep 16 '13 at 07:50