如何解决C ++:在成员变量的指针传递到其他地方的情况下,如何使编译器优化内存访问
[edit:这是动机:将变量的指针传递给外部函数可能会意外中断对“相邻”变量的某些优化,因为可能会导致指针指向由原始指针计算出的相邻变量外部功能。以下是原始文章,其中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
的负载是不安全的。
[edit:再三考虑,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;
}
不幸的是,它仍然无法正常工作。
我的问题是:
P.S。以下代码针对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;
}
解决方法
使用offsetof
从T::a
到达T::b
是非法的,因为没有对象pointer-interconvertible和T::b
,T::a
来自{可以到达。在另一个方向上,possible从T::b
到达T::a
,因为后者可以与T
进行指针互转换。在注释中与Peter相反(尽管在Linux内核中存在container_of
宏),&t.b - 1
不会产生指向t.a
的指针,因为T::b
和{{1} }不可指针互换。
请注意,给定指向T::a
的指针,您仍然需要使用std::launder
来访问T::a
:
T::b
因此,具有足够侵略性的编译器确实可以得出结论,给定指向auto p = &t.a;
std::launder(reinterpret_cast<T*>(p))->b = 1;
的指针,没有替代项f
可以访问t.a
。但是,目前似乎没有主流编译器执行此优化。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。