mercredi 25 juillet 2018

RVO and Move Semantics in Objective-C++

TL;DR: Does the __block attribute on an std::vector prevent RVO in Objective-C++?

In Modern C++, the canonical way to return a vector from a function is to just return it by value so that return value optimization can be used if possible. In Objective-C++, this appears to work the same way.

- (void)fetchPeople {
  std::vector<Person> people = [self readPeopleFromDatabase];
}

- (std::vector<Person>)readPeopleFromDatabase {
  std::vector<Person> people;

  people.emplace_back(...);
  people.emplace_back(...);

  // No copy is made here.
  return people;
}

However, if the __block attribute is applied to the second vector, then it appears that a copy of the vector is being created when it returns. Here is a slightly contrived example:

- (std::vector<Person>)readPeopleFromDatabase {
  // __block is needed to allow the vector to be modified.
  __block std::vector<Person> people;

  void (^bloc)() = ^ {
    people.emplace_back(...);
    people.emplace_back(...);
  };


  block();

  #if 1

  // This appears to require a copy.
  return people;

  #else

  // This does not require a copy.
  return std::move(people);

  #endif
}

There are plenty of Stack Overflow questions that explicitly state that you don't need to use std::move when returning a vector because that will prevent copy elision from taking place.

However, this Stack Overflow question states that there are, indeed, some times when you do need to explicitly use std::move when copy elision is not possible.

Is the use of __block in Objective-C++ one of those times when copy elision is not possible and std::move should be used instead? My profiling appears to confirm that, but I'd love a more authoritative explanation.

(This is on Xcode 10 with C++17 support.)

Aucun commentaire:

Enregistrer un commentaire