c++ - C++:在成员变量的指针传递到其他地方的情况下,如何使编译器优化内存访问

标签 c++ optimization member-variables offsetof

[编辑:这是动机:将变量的指针传递给外部函数可能会意外中断对“相邻”变量的某些优化,因为可能会获得外部函数从原始指针计算出的相邻变量的指针。以下是原始文章,其中volatile用于模拟当前编译器单元无法访问的外部函数,例如虚拟函数调用,封闭源代码库函数等]
我想知道以下代码中的return t.a;是否将优化为return 0;

//revision 1
struct T
{
    int a;
    int b;
};

void f_(int * p)
{
    *p = 1;
}
auto volatile f = f_;

int main()
{
    T t;
    t.a = 0;
    t.b = 0;
    for (int i = 0; i < 20; ++i)
    {
        f(&t.b);
    }
    return t.a;
}
好吧it's not
相当公平,因为函数f中的代码可以使用offsetof获取指向t的指针,然后更改t.a
因此,优化掉t.a的负载并不安全。
[编辑:再三考虑,在这里offsetof是不够的。我们需要container_of,似乎无法在标准C++中实现。]
但是offsetof不能用于非标准布局类型。所以我尝试了以下代码:
//revision 2
#include <type_traits>

struct T
{
private:
    char dummy = 0;
public:
    int a;
    int b;
};
static_assert(!std::is_standard_layout_v<T>);

void f_(int * p)
{
    *p = 1;
}
auto volatile f = f_;

int main()
{
    T t;
    t.a = 0;
    t.b = 0;
    for (int i = 0; i < 20; ++i)
    {
        f(&t.b);
    }
    return t.a;
}
不幸的是,它仍然无法正常工作。
我的问题是:
  • 在上述情况下,安全地优化t.a的负载是否安全(修订版2)
  • 如果不是,是否存在/建议中存在一些安排以使其成为可能? (例如,将T设置为更特殊的类型,或者将b中的成员T设置为属性说明符)

  • 附言以下代码针对return t.a;进行了优化,但是循环产生的代码效率低下。
    而且,临时变量变戏法很麻烦。
    //revision 3
    struct T
    {
        int a;
        int b;
    };
    
    void f_(int * p)
    {
        *p = 1;
    }
    auto volatile f = f_;
    
    int main()
    {
        T t;
        t.a = 0;
        t.b = 0;
        for (int i = 0; i < 20; ++i)
        {
            int b = t.b;
            f(&b);
            t.b = b;
        }
        return t.a;
    }
    

    最佳答案

    因为没有对象offsetofT::a可以从中获取T::b,所以使用T::bT::a中获取T::b是非法的。在另一个方向上,从T::a到达Tpointer-interconvertible,因为后者可以与container_of进行指针互转换。在注释中与Peter相反(尽管在Linux内核中存在possible宏),但&t.b - 1不会产生指向t.a的指针,因为T::bT::a不可指针互换。
    注意,给定指向T::a的指针,您仍然需要使用 std::launder 来访问T::b:

    auto p = &t.a;
    std::launder(reinterpret_cast<T*>(p))->b = 1;
    
    因此,具有足够侵略性的编译器确实可以得出结论,给定f的指针,没有替代的t.a可以访问t.b。但是,目前似乎没有主流编译器执行此优化。

    关于c++ - C++:在成员变量的指针传递到其他地方的情况下,如何使编译器优化内存访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64621479/

    相关文章:

    c++ - 在 C++ 程序中制作全局结构

    mysql - 优化innodb表: yes or no?

    c++ - Qt中给成员变量设置父子关系

    c++ - 成员变量如何与专门的类模板一起使用?

    c++ - 返回成员变量的引用是不好的做法吗?

    C++11 字符串初始化

    c++ - 无法使用基类构建 DLL

    c# - 为什么故意不优化这个循环?

    c++ - Apache HTTP 服务器 - 如何在模块上打印到控制台?

    mysql - 如何将查询存储到变量中以便我可以使用它两次?