在以下代码中:
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。但是,可能对于这种特殊情况,指针算法会起作用吗?
答案 0 :(得分:1)
答案是:这取决于编译器!
如果你有64位编译器且sizeof(Previous)
是4且T
是指针数据类型,则编译器(至少大多数编译器)将在previous
和value
之间添加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;
}
}
}
的任何对象(例如本地变量)。