C ++使用指针算法获取parrent类

时间:2017-08-15 19:36:18

标签: c++

在以下代码中:

using Previous = std::atomic<void*>;
template<class T>
struct Element{
    Previous previous;
    T value;
}

我是否可以通过指针算法从Element<T>*获取T*? 像这样:

template<class T>
Element<T>* getElement(T* value){
   return static_cast<Element<T>*>(static_cast<void*>(reinterpret_cast<unsigned char *>(value) - sizeof(Previous)));
}

T可能是非标准布局。

P.S。我清楚地看到我不能使用offsetof。但是,可能对于这种特殊情况,指针算法会起作用吗?

1 个答案:

答案 0 :(得分:1)

答案是:这取决于编译器!

如果你有64位编译器且sizeof(Previous)是4且T是指针数据类型,则编译器(至少大多数编译器)将在previousvalue之间添加4个额外字节(void *)(((unsigned char *)value) - sizeof(Previous)

你使用的指针:

previous

...在这种情况下指向sizeof(Previous)之后的第一个字节!

但是,您可以使用以下表达式替换(int)&(((Element *)NULL)->value)

NULL

(很抱歉,上面的表达式是C表达式;我的C ++不是最好的。)

此表达式应始终为常量:父结构中元素的地址偏移量。

修改

理论上可能会有编译器执行((int)&(x.value) - (int)&x) 指针检查,这会在使用上面的表达式时导致错误。

在这种情况下,以下表达式将完成此任务:

x

...虽然Element数据类型public class ApiAuthenticationMiddleware { private readonly RequestDelegate _next; private readonly UserManager<ApplicationUser> _userManager; private readonly SignInManager<ApplicationUser> _signInManager; public ApiAuthenticationMiddleware(RequestDelegate next, SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> usermanager) { _next = next; _signInManager = signInManager; _userManager = usermanager; } public async Task Invoke(HttpContext context) { if (!context.Request.Query.ContainsKey("password") || !context.Request.Query.ContainsKey("email")) { context.Response.StatusCode = 401; //UnAuthorized await context.Response.WriteAsync("Invalid User Key"); return; } var email = context.Request.Query["email"]; var password = context.Request.Query["password"]; var result = await _signInManager.PasswordSignInAsync(email, password, false, lockoutOnFailure: false); if (result.Succeeded) { await _next.Invoke(context); } else if (//some more checks) context.Response.StatusCode = 401; //UnAuthorized await context.Response.WriteAsync("Invalid User Key"); return; } } } 的任何对象(例如本地变量)。