c++ - 对数组中特定位置的调试器友好的零成本命名引用

标签 c++ c++14

struct A
{
    int a   = 1;
    short b = 2;
    char c  = 3;
}

struct B
{
    using arr_type = array<A,3>;
    char asd = 0;
    A a1;  
    A a2;
    A a3;

    // is this safe to use to loop trough all 3 elements?
    arr_type* p1 = reinterpret_cast<arr_type*>(&a1);

    // or maybe this one?
    A* p2 = &a1;
};

我可以安全地使用 p1p2a1...a3 开始循环吗?

B b;

for (int i = 0; i < 3; i++)
{
     cout << p1[i];
     cout << p2[i];
}

之所以不是简单的数组,是因为我希望每个“项目”都有一个合适的名称。

我可以改为使用 union 方法,但 C++ 禁止匿名结构(虽然这对我来说不是问题,因为 MSVC 支持这个并且 GCC 似乎也支持它);

union E
{
    A arr[3];
    struct {
        A a1;
        A a2;
        A a3;
    };
};

下面显然是安全的,但它对每个引用都有 4 字节的开销。我不喜欢。 (加上初始化引用的成本..)

struct B
{
    char asd;
    A arr[3];  
    A& a1 = arr[0];
    A& a2 = arr[1];
    A& a3 = arr[2];
};

这个没有开销,但对于我非常具体的情况,它还不够好。

struct B
{
    char asd;
    A arr[3];  
    A& a1() { return arr[0] };
    A& a2() { return arr[1] };
    A& a3() { return arr[2] };
};

我将经常使用那些 a1、a2、a3 名称,如果它们是 visual studio 中的函数调用,则很难调试它们。而且,我将经常使用这些字段,因此我希望能够轻松检查它们的值。

最佳答案

struct B
{
     using arr_type = array<A,3>;
     char asd = 0;
     A a1;  
     A a2;
     A a3;

     // is this safe to use to loop trough all 3 elements?
     arr_type* p1 = reinterpret_cast<arr_type*>(&a1);
 };

结构需要自然对齐它们的类型,数组也是如此,但我不知道有任何规则说它们必须是相同的对齐点。

如果这样的规则,像这样的成员结构布局边界和数组边界将相同——它只适用于标准布局结构:

https://stackoverflow.com/a/7189821/211160

如果你做了类似的事情,所有的赌注都会被取消:

private:
    A a1;
    A a2;
public:
    A a3;

如果它包含触发标准布局开关的任何内容,我想所有的赌注都会被取消。由于一开始是有问题的,所以我会说那时候甚至不要这样做。

(我还想知道 #pragma pack() 会给数组和结构带来什么样的差异...并不是说 #pragmas 在标准中,我只是奇怪。)

union E
{
    A arr[3];
    struct {
        A a1;
        A a2;
        A a3;
    };
};

不,arr[N]aN 不等价。关于如何在 union 中使用初始序列以在 C++ 中进行兼容的读取,有一些微妙的细节...但这仅适用于具有兼容序列的结构。它没有提到结构和数组:

Type punning a struct in C and C++ via a union

I'm gonna be using those a1, a2, a3 names very often, and it's harder to debug them if they are function calls in visual studio. And again, I'm going to be using those fields a lot, so I want to be able to check their values easily.

"And the following is clearly safe, but it has a 4 byte overhead for each reference"

在实践中看起来你是对的,今天的 GCC 并没有优化它(根据你的链接):

https://godbolt.org/g/6jAtD5

http://ideone.com/zZqfor

这令人失望,它们可以被优化掉,因为标准中没有任何内容说它们必须占用空间。它们在内部指向结构,并且在结构的生命周期内不会改变。 :-/

您对将被优化掉的函数访问的提示是它对调试器不够友好。为什么不两者都做?

struct B
{
    char asd;
    A arr[3];

    A& a1() { return arr[0] }
    const A& a1() const { return arr[0]; }
    A& a2() { return arr[1] };
    const A& a2() const { return arr[1]; }
    A& a3() { return arr[2] };
    const A& a3() const { return arr[2]; }

#if !defined(NDEBUG)
    A& a1_debug = arr[0];
    A& a2_debug = arr[1];
    A& a3_debug = arr[2];
#endif
};

如果投影数据结构的调试器友好特性对您很重要...那么花时间学习如何为您的环境编写自定义调试器助手可能是一个很好的选择,例如:

http://doc.qt.io/qtcreator/creator-debugging-helpers.html

我想这是否值得取决于您有这种担忧的频率。

关于c++ - 对数组中特定位置的调试器友好的零成本命名引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36466876/

相关文章:

c++ - 在模板中使用模板实例类型

c++ - 5 与 std::move(5) 的行为差异

C++ move 语义 - 包装遗留 C API

c++ - Unsigned Long Long 超出范围?

c++ - 可以使用十六进制编辑器从 exe 文件中删除代码吗? (c++)

c++ - 头文件中的重复类声明

c++ - 如何声明一个对象但不运行构造函数?

c++ - 引用的使用

c++ - IF 内有两个语句的简写 If/Else 语句

c++ - §7.1.6.3/1 (C++14) 不接受下面第二个片段中的构造。为什么是这样?