Проблема компилятора g ++ с выровненным_сторгом - это ошибка компилятора? - PullRequest
0 голосов
/ 22 марта 2020

Я скопировал приведенную ниже программу из этой ссылки

#include <iostream>
#include <type_traits>

struct A {  // non-POD type
  int avg;
  A (int a, int b) : avg((a+b)/2) {}
};

typedef std::aligned_storage<sizeof(A),alignof(A)>::type A_pod;

int main() {
  A_pod a,b;
  new (&a) A (10,20);
  b=a;
  std::cout << reinterpret_cast<A&>(b).avg << std::endl;

  return 0;
}

Я запустил gdb для этого кода, чтобы понять размер различных компонентов, и результаты приведены ниже:

(gdb) b 18
Breakpoint 1 at 0x96d: /home/ripunjay/study/bitbucket/study/cpp/aligned_storage.cpp:18. (3 locations)
(gdb) r
Starting program: /home/ripunjay/study/bitbucket/study/cpp/aligned_storage 

Breakpoint 1, _GLOBAL__sub_I_main () at aligned_storage.cpp:18
18  }
(gdb) ptype a
type = const union {
    int i[2];
    double d;
}
(gdb) ptype A_pod
type = union std::aligned_storage<4, 4>::type {
    unsigned char __data[4];
    struct {
        <no data fields>
    } __align;
}
(gdb) ptype A_
No symbol "A_" in current context.
(gdb) ptype A
type = struct A {
    int avg;
  public:
    A(int, int);
}
(gdb) p sizeof(A)
$1 = 4
(gdb) p sizeof(a)
$2 = 8
(gdb) p sizeof(b)
$3 = 8

(gdb) ptype A
type = struct A {
    int avg;
  public:
    A(int, int);
}

Позже, чтобы увидеть нормальный вызов конструктора, я добавил одну строку в main () для создания объекта c следующим образом -

int main() {
  A_pod a,b;
  A c(10,20);
  new (&a) A (10,20);
  b=a;
  std::cout << reinterpret_cast<A&>(b).avg << std::endl;

  return 0;
}

Это вызвало определения размеров и даже типов для а и б поменять. Было довольно удивительно, что даже если эта добавленная строка закомментирована, компилятор ведет себя по-другому.

(gdb) r
Starting program: /home/ripunjay/study/bitbucket/study/cpp/aligned_storage 
15

Breakpoint 1, main () at aligned_storage.cpp:18
18    return 0;
(gdb) ptype a
type = union std::aligned_storage<4, 4>::type {
    unsigned char __data[4];
    struct {
        <no data fields>
    } __align;
}
(gdb) ptype b
type = union std::aligned_storage<4, 4>::type {
    unsigned char __data[4];
    struct {
        <no data fields>
    } __align;
}
(gdb) ptype A_pod
type = union std::aligned_storage<4, 4>::type {
    unsigned char __data[4];
    struct {
        <no data fields>
    } __align;
}


g++ --version 
g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

1 Ответ

1 голос
/ 23 марта 2020

При этом std::cout << reinterpret_cast<A&>(b).avg << std::endl; ваша программа демонстрирует неопределенное поведение. Почему? Вы используете неинициализированное значение.

Что это значит? Этот компилятор может делать все что угодно. И под всем, что я имею в виду буквально все, что угодно, в том числе взорвать ваш компьютер, - это разрешено стандартом. И поэтому не удивительно видеть изменение размеров шрифта / отступов / выравнивания и т. Д. В gdb. Компилятору разрешено делать это, поскольку вы вошли в область undefiend bahaviour.

ИМХО, но нет простого способа убедиться в этом из-за изменения размера / выравнивания UB class A. Поскольку он изменил, внутреннее устройство std::aligned_storage изменилось вместе с ним (поскольку выровненные внутренние компоненты хранилища могут иметь очень разные внутренние представления для разных пар размер / выравнивание).

...