当前位置: 首页 > wzjs >正文

做网站需要看那几点2019销售网站开发与设计现状

做网站需要看那几点,2019销售网站开发与设计现状,网站主要内容,wordpress 淘宝分享插件下载1.背景 理论上,指针并不是一个简单表示地址的整数,而是标识一个对象的东西,并不一定要与地址关联。 因此,指针不会随意的访问到另一个不相关的对象,即使两个指针指向相同的地址。 当对象的生命周期结束后,其…

1.背景

        理论上,指针并不是一个简单表示地址的整数,而是标识一个对象的东西,并不一定要与地址关联。 因此,指针不会随意的访问到另一个不相关的对象,即使两个指针指向相同的地址。 当对象的生命周期结束后,其指针也会失效,即使后续对象占用原对象的空间,它也不会随意变成新对象的合法指针。

        常见的不可重用的例子为:类 T 包含非静态 const 数据成员 或 引用数据成员,则在 x 上创建新的 T 对象,原本 x 的指针、引用都不会重新指向新的对象 。

        其实是关于 C++ 17 标准库中 std::optional<T> 实现过程中遇到的问题的讨论。假如你是库的作者,这是一个  std::optional<T> 的实现,你能看出来它存在什么问题吗?

template<typename T>
class optional {
private:T payload;
public:optional(const T& t) : payload(t) {}template<typename... Args>void emplace(Args&&... args) {//结束对象的生存期payload.~T();//原地构造新对象,但使用旧对象的指针::new (&payload) T(std::forward<Args>(args)...);    // *}const T& operator*() const & {return payload;   // Not OK//return *(std::launder(&payload));   // OK//也可以拿一个指针成员保存 placement new 的返回结果,但显然很麻烦}
};struct A {constexpr A(int &x) : ref(x) {}int &ref;
};int main() {int n1 = 0, n2 = 0;optional<A> opt2 = A(n1);opt2.emplace(n2);std::cout << opt2.ref << std::endl; //?
}

是的,它的问题就是会触发 UB(Undefined Behavior未定义行为),当我们在 payload 的存储位置上创建新对象以后,因为 A 存在引用类型成员,导致通过原始 payload 访问 ref 成员的时候,有可能访问的是原始绑定的 n1。同样,解决方案是引入 std::launder() 函数,如果不使用 std::launder() 函数,则解决方案就只能是这样:

template<typename T>
class optional {
private:T payload;T *p;
public:optional(const T& t) : payload(t) {p = &payload;}template<typename... Args>void emplace(Args&&... args) {payload.~T();p = ::new (&payload) T(std::forward<Args>(args)...);    // *}const T& operator*() const & {return *p;   // 不使用 &payload}
};

这里引入了一个指针 p,用于保存 placement new 的返回值。因为编译器知道 p 是个新对象的地址,对 p 的访问将会重新开始,不存在之前基于 payload 地址上的优化干扰,行为是明确的,不会产生 UB。但是这种做法也引入了一点开销,这是标准库不能接受的。

2.std::launder简介

   std::launder 是 C++17 引入的一个标准库函数模板,主要用于处理对象生命周期结束后,通过指针访问新创建对象时的 ** 指针 “清洗”(pointer laundering)** 问题,避免因编译器优化导致的未定义行为(Undefined Behavior, UB)。

        通俗的讲,std::launder() 函数的核心作用是显式告知编译器:指针所指向的内存内容可能已被外部修改(比如对象已经重新构造),需要重新加载数据(不能再使用优化器之前针对这个地址访问的时候产生的缓存),确保后续对指针的访问正确反映新对象的实际类型。

3.可触及性(reachability)限制

        通过 std::launder() 函数可以得到源指针被“清洗”后的新指针(指向同一个地址),新指针的访问可触及性不能超过源指针,也就是说,通过源指针不能访问的的位置,通过新指针也是不能访问的。可以这么理解,对一个地址“清洗”的范围是有限的,通过新指针访问超过可触及范围的内容,依然是 UB。这是一个比较让人疑惑的点,我们来看看 std::launder() 函数的原型:

template< class T >
constexpr T* launder( T* p ) noexcept;

既然源指针 p 和返回的新指针都是同一个类型,怎么会产生不同的可触及范围呢?答案是当它遇到 reinterpret_cast 的时候。因为 reinterpret_cast 可以在不改变地址可触及范围的情况下改变指针的类型,比如这段代码:

struct A { int a; int b; };
struct B { int y; };std::byte bytebuf[sizeof(A)];
B* pb = new (bytebuf) B{ 5 };
A* pa = reinterpret_cast<A*>(pb); //UB

虽然使用 reinterpret_cast 可以将 B* 指针转换成 A* 指针,但是结果 pa 的可访问范围仍然是和 pb 的范围一样。当它叠加到 std::launder() 函数的时候,就会出现违反可触及性限制的情况,比如:

A* pa = std::launder(reinterpret_cast<A*>(pb)); //OK
int c = pa->b; //UB

另一个可能违反可触及性的场景是配合数组使用的时候,指向数组元素的指针和数组的地址经常把人搞晕。来看这个例子:

struct Y { int a[10]; double y; } x5;auto p5 = std::launder(reinterpret_cast<int(*)[10]>(&x5.a[0]));

&x5.a[0] 的类型实际上是 int*,所以它能访问的范围就是 x5.a 这个数组,但是我们用 reinterpret_cast 把它强转成 int[10] 类型的指针,但是并不改变它的可触及范围(依然是 x5.a 这个数组)。再用 std::launder() 洗它,得到一个新的 int[10] 类型的指针,它指向的新对象(数组)的位置就位于 x5 内部,地址上与 x5 重叠,理论上,它可以访问整个 x5,这就违反了可触及性限制,会导致 UB。

4.典型应用场景

以下情况通常需要使用 std::launder

1)在已销毁对象的内存上构造新对象:当通过 placement new 在原对象内存上构造新对象(类型可能不同)时,需要用 std::launder 获取新对象的有效指针。

2)访问被覆盖的多态对象:如果新对象是原对象的派生类(或反之),或涉及虚函数表(vtable),直接使用原指针可能导致访问错误的虚函数表,需用 std::launder 修正。

 尽管上述描述已经对标准上的说法做了重新理解,但是这两句话依然还是有点抽象,我个人喜欢将其转化成以下三种适配场景:

  • 在已存在的存储空间上构造新对象(如 placement new);

  • 通过 reinterpret_cast 或 memcpy() 函数修改对象的动态类型;

  • 多态对象的内存布局变化(如通过 union 修改活跃成员,在 Base 对象存储位置上创建 Derived 对象)。

示例代码如下:

#include <new>
#include <cstddef>
#include <cassert>struct X {const int n; // 注意: X 拥有 const 成员int m;
};struct Y {int z;
};struct A { virtual int transmogrify();
};struct B : A {int transmogrify() override { new(this) A; return 2; }
};int A::transmogrify() { new(this) B; return 1; }static_assert(sizeof(B) == sizeof(A));int main()
{X *p = new X{3, 4};const int a = p->n;X* np = new (p) X{5, 6};    // p 不指向新对象,因为 X::n 为 const ,而 np 指向新对象const int b = p->n; // 未定义行为const int c = p->m; // 未定义行为(即使 m 为非 const ,也不能用 p )const int d = std::launder(p)->n; // OK : std::launder(p) 指向新对象const int e = np->n; // OKalignas(Y) std::byte s[sizeof(Y)];Y* q = new(&s) Y{2};const int f = reinterpret_cast<Y*>(&s)->z; // 类成员访问为未定义行为:// reinterpret_cast<Y*>(&s) 拥有值“指向 s 的指针”// 而非指向 Y 对象const int g = q->z; // OKconst int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OKA i;int n = i.transmogrify();// int m = i.transmogrify(); // 未定义行为int m = std::launder(&i)->transmogrify(); // OKassert(m + n == 3);
}

5.std::launder和reinterpret_cast的区别

std::launder 和 reinterpret_cast 都可以用于指针类型的转换,但它们有以下区别:

功能目的

  • std::launder 主要用于处理在对象生命周期结束后,在同一内存位置创建新对象时,更新指针的类型信息,以确保对新对象的正确访问,避免编译器优化导致的未定义行为。
  • reinterpret_cast 是一种较为底层的强制类型转换,用于将一种指针类型转换为另一种指针类型,它可以在不同类型的指针之间进行任意转换,包括不相关的类型。

安全性

  • std::launder 是在遵循 C++ 内存模型和对象生命周期规则的前提下,安全地更新指针类型,只要正确使用,不会导致未定义行为。
  • reinterpret_cast 的转换相对不安全,因为它可以进行各种不保证兼容性的指针转换。如果转换后的指针类型与实际指向的对象类型不匹配,在访问对象时可能会导致未定义行为。

适用场景

  • std::launder 适用于在特定的内存管理场景中,如在已销毁对象的内存上构造新对象,或者涉及对象类型替换且需要确保编译器正确处理指针类型的情况。
  • reinterpret_cast 适用于一些底层的、与硬件相关的编程,或者在需要对指针进行特殊的、不遵循常规类型规则的转换时使用,但要谨慎使用,以免引发错误。

示例代码:

#include <iostream>
#include <new>struct OldType { int value; };
struct NewType { int value; };int main() {// 分配内存alignas(OldType) unsigned char buffer[sizeof(OldType)];// 构造OldType对象OldType* old_ptr = new(buffer) OldType{42};// 析构OldType对象old_ptr->~OldType();// 在同一块内存构造NewType对象NewType* new_ptr_raw = new(buffer) NewType{100};// 使用std::launder获取正确的指针NewType* new_ptr_launder = std::launder(new_ptr_raw);std::cout << "New value (std::launder): " << new_ptr_launder->value << std::endl;// 使用reinterpret_cast进行转换NewType* new_ptr_reinterpret = reinterpret_cast<NewType*>(old_ptr);// 可能导致未定义行为,因为reinterpret_cast没有考虑对象生命周期和类型变化std::cout << "New value (reinterpret_cast): " << new_ptr_reinterpret->value << std::endl;return 0;
}

在上述代码中,std::launder 能够正确处理指针类型的更新,而 reinterpret_cast 虽然进行了指针类型转换,但没有考虑对象生命周期的变化,可能导致未定义行为。 

6.注意事项

1)内存必须重叠:新对象必须完全覆盖原对象的内存空间(即使用同一块 buffer),否则 std::launder 无法生效。

2)类型需合法:新对象的类型不能是原对象的 “严格别名规则” 禁止的类型(例如不能用 std::launder 将 int* 转为 float*,除非符合别名规则)。

3)非万能工具std::launder 不能修复非法内存访问(如越界指针或已释放的内存),仅用于处理 “对象替换后指针类型信息过时” 的问题。

7.总结

        std::launder() 函数不会对入参的地址做任何操作,所以 std::launder() 函数总是异常安全的。实际上,std::launder() 函数不会产生任何运行开销,它只是标准库和编译器的一个私有协议,编译器看到 std::launder() 函数就做该做的事情。C++ 很多语言特性是由标准库中的代码提供的,并且库和用户代码是平权的,标准库能做的事情,用户代码也能做。但是也有部分内容是需要库和编译器配合的,比如协程,operator new 之类的,本篇介绍的 std::launder() 函数也算一个。

  而且std::launder 是 C++ 中处理低层次内存管理(如自定义容器、内存池)的重要工具,其核心价值是通过显式告知编译器指针的 “类型更新”,避免因优化导致的未定义行为。使用时需严格遵循内存重叠和类型合法性的约束。

参考:

std::launder_C++中文网


文章转载自:

http://lBf3xu1g.ncLbk.cn
http://OlxqBWMm.ncLbk.cn
http://ZkRK4SEW.ncLbk.cn
http://gMse3IPP.ncLbk.cn
http://typNj3j6.ncLbk.cn
http://QnjgWhTQ.ncLbk.cn
http://zXpnbE8m.ncLbk.cn
http://sI84LQiL.ncLbk.cn
http://lYjoIg2M.ncLbk.cn
http://zUTr04jj.ncLbk.cn
http://pP2kQh1L.ncLbk.cn
http://GYrOOY2r.ncLbk.cn
http://2z6V7rNS.ncLbk.cn
http://3c7wt0zQ.ncLbk.cn
http://vBWgBPrY.ncLbk.cn
http://x6v61OeB.ncLbk.cn
http://UASn8q1n.ncLbk.cn
http://IRbvczjg.ncLbk.cn
http://zgw6fYgH.ncLbk.cn
http://WZongywe.ncLbk.cn
http://FZei6WCt.ncLbk.cn
http://XQ82QzqB.ncLbk.cn
http://uXMMrYUA.ncLbk.cn
http://2wP3heiQ.ncLbk.cn
http://WGkPErn8.ncLbk.cn
http://aV1fmECQ.ncLbk.cn
http://d8yB1mFL.ncLbk.cn
http://jgOfb6QS.ncLbk.cn
http://xc28q1ax.ncLbk.cn
http://nPoDcplg.ncLbk.cn
http://www.dtcms.com/wzjs/750421.html

相关文章:

  • 全面的郑州网站建设网站建设是要考虑什么东西
  • 珠海网站优化培训wordpress模板开发教程
  • 网站属性设置分类信息建站系统
  • 佛山企业建网站科技魏玄成
  • x站源码免费分享学校网站建设介绍范文
  • 产品推广渠道有哪些方式深圳百度seo优化
  • 电影订票网站怎么做页游平台排行榜
  • 武进网站建设怎么样国内自动化网站建设
  • 上海专业网站营销做易经类的网站
  • 做电影网站有哪些建设银行手机个人网站
  • 品牌网站建设 细致磐石网络有没有做任务的网站
  • 建筑学生的网站wordpress创建页面地址设置
  • 天津市建设快速seo排名优化
  • 能进封禁网站的浏览器佛山本地网站建设
  • 国内装饰行业网站开发自己做的网站怎么推广
  • 建设部执业资格注册中心网站做泵阀生意到哪个网站
  • 网站公司推荐直播app开发公司排名
  • 做故障风的头像的网站wordpress主题设置框架
  • 怎么创造自己的网站建筑培训
  • 网站备案帐号网上做视频赚钱的网站
  • 手机做网站价格柳州市诚信体系建设网站
  • 如何网站建设平台网站开发有什么好的论坛
  • wordpress做网站优点网址大全名称
  • 如何查公司网站开发时间自建网站软件
  • 中国建设银行驻莫斯科网站网站 如何备案
  • 微山网站建设多少钱网站实名审核多久
  • 网站后台动态播放怎么做的网站建设从初级到精通
  • 代理IP做网站html编辑器在哪
  • 网站制作免费软件专业做家居的网站有哪些
  • 网站运营的具体工作包括哪些网站在线制作软件