【问题标题】:g++ compiler issue with aligned_storage - Is this a compiler bug?对齐存储的 g++ 编译器问题 - 这是编译器错误吗?
【发布时间】:2020-03-22 16:47:13
【问题描述】:

我从这个link复制了下面的一个程序

#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;
}

这导致 a 和 b 的大小甚至类型定义发生变化。令人惊讶的是,即使注释掉了这个新添加的行,编译器也会有不同的行为。

(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.

【问题讨论】:

  • b 未初始化,因此您的程序具有未定义的行为
  • reinterpret_cast&lt;A&amp;&gt;(b).avg 表现出未定义的行为,通过在对象(A 类型)的生命周期开始之前访问它。
  • @IgorTandetnik - 我根本不看 cout 的输出 - 我更喜欢看 gdb 和 sizeof。请让我知道它是如何由未初始化的 b 控制的。另请查看两种情况下 a 和 b 的定义。

标签: c++ c++11 templates c++14 generic-programming


【解决方案1】:

通过这样做std::cout &lt;&lt; reinterpret_cast&lt;A&amp;&gt;(b).avg &lt;&lt; std::endl;,您的程序会表现出未定义的行为。为什么?您使用未初始化的值。

这意味着什么?该编译器被允许做任何事情。我的意思是任何东西,包括炸毁你的电脑——这是标准允许的。因此,在 gdb 中看到类型大小/填充/对齐等方面的变化也就不足为奇了。编译器可以这样做,因为你进入了不法行为的领域。

恕我直言,但由于 class A 的 UB 大小/对齐方式已更改,因此没有简单的方法可以确定。因为它改变了 std::aligned_storage 的内部结构(因为对齐的存储内部结构对于不同的大小/对齐对可以有非常不同的内部表示)。

【讨论】:

    猜你喜欢
    • 2012-08-05
    • 1970-01-01
    • 2021-04-24
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 2013-03-13
    • 2013-11-28
    • 1970-01-01
    相关资源
    最近更新 更多