Frage Ist die "Punning-Regel" für das erste Element des Standardlayouts auf Arrays erweitert?


Insbesondere umschließe ich eine C-API in einem freundlichen C ++ - Wrapper. Die C-API hat diese ziemlich standardmäßige Form:

struct foo {...};
void get_foos(size_t* count, foo* dst);

Und was ich würde mögen zu tun, ist mir eine zusätzliche Kopie speichern, indem Sie eine typisierte Hülle übergeben Array direkt zum CAPI mit einer Reihe von Gesundheitsüberprüfungen static_assert().

class fooWrapper {
  foo raw_;
public:
   [...]
};

std::vector<fooWrapper> get_foo_vector() {
  size_t count = 0;
  get_foos(&count, nullptr);

  std::vector<fooWrapper> result(count);

  // Is this OK?
  static_assert(sizeof(foo) == sizeof(fooWrapper), "");
  static_assert(std::is_standard_layout<fooWrapper>::value, "");
  get_foos(&count, reinterpret_cast<foo*>(result.data()));

  return result;
}

Ich verstehe, dass es sich um einen gültigen Code handelt, da alle Speicherbereiche, auf die zugegriffen wird, sich unter der Regel einzeln qualifizieren, aber ich möchte eine Bestätigung dafür erhalten.

Bearbeiten: Natürlich, solange reinterpret_cast<char*>(result.data() + n) == reinterpret_cast<char*>(result.data()) + n*sizeof(foo) ist wahr, wird es Arbeit unter allen großen Compilern heute. Aber ich frage mich, ob der Standard stimmt.


7
2018-06-07 18:48


Ursprung


Antworten:


Erstens ist dies keine Art Punning. Das reinterpret_cast Sie tun, ist nur eine überschriftliche Art zu tun &result.data().foo_. Typ Punning greift auf ein Objekt eines Typs über einen Zeiger / Verweis auf einen anderen Typ zu. Sie greifen auf ein Unterobjekt des anderen Typs zu.

Zweitens funktioniert das nicht. Zeigerarithmetik basiert auf einem Array (Ein einzelnes Objekt fungiert als ein Array von 1 Element für die Zwecke der Zeigerarithmetik). Und vector<T> ist durch Fiat definiert, um ein Array von zu erzeugen Ts. Aber eine Reihe von T ist nicht äquivalent zu einem Array eines Unterobjekts von T, auch wenn dieses Unterobjekt die gleiche Größe wie T und T ist Standard-Layout.

Daher, wenn get_foos führt Zeigerarithmetik auf seinem gegebenen Array von aus foos, das ist UB. Oh sicher, es wird fast sicher Arbeit. Aber die Antwort der Sprache ist UB.


5
2018-06-07 23:02