移动语义、标准集合和构造时间地址
Move semantics, standard collections, and construction time address
我当然想知道一些神奇的解决方案,但我对重组持开放态度。
因此,我有一个类DeviceDependent
,具有以下构造函数
DeviceDependent(Device& device);
其存储对该设备的引用。设备可以更改状态,这将需要更改依赖于该设备的所有DeviceDependent
实例。(你猜到了,这是我骑directX野兽的微不足道的尝试)
为了处理这个问题,我有函数DeviceDependent::createDeviceResources()
、DeviceDependent::onDeviceLost()
。
我计划将每个DeviceDependent
实例注册到DeviceDependent
构造函数中指定的设备。设备将保持如此注册的所有DeviceDependent
实例的std::vector<DeviceDependent*>
。然后,它将遍历该向量,并在适当的时候调用上面的函数。
这看起来很简单,但我特别喜欢的是,我可以在代码中的其他地方使用std::vector<DeviceDependent (or child)>
,并快速迭代它们。例如,我有一个类Renderable
,顾名思义,它表示一个可渲染对象,我需要至少每帧迭代一次,因此我不希望对象分散在整个内存中。
归根结底,问题是:
当我创建实体对象时,我依赖于移动语义。这纯粹是出于本能,我没有考虑复制像这样的大对象来将它们添加到std::vector<DeviceDependent (or child)>
集合中。
然而,使用移动语义(我已经为那些不相信它的人测试了这一点),对象的地址会发生变化。更重要的是,在调用默认构造函数后,它会发生变化。这意味着我在调用device.registerDeviceDependent(this)
的DeviceDependant
构造函数中的代码编译和运行良好,但设备会累积一个指针列表,一旦对象移动到向量中,这些指针就会失效。
我想知道是否有办法让我坚持这个计划并使它发挥作用。
我想到的事情:
使"real"矢量成为共享指针的集合,复制没有问题。对象大概不会更改地址。我不喜欢这个计划,因为我担心把东西放在堆里会损害迭代性能。
在对象被移动后调用register,这是我暂时要做的事情,但我不喜欢它,因为我觉得构造函数是做这件事的合适地方。那里不应存在不在某个设备清单上的
DeviceDependent
实例。编写自己的移动构造函数或移动赋值函数。通过这种方式,我可以从设备中删除旧地址,并将其更改为新地址。我不想这样做,因为我不想随着类的发展不断更新它。
这与移动构造函数无关。问题是std::vector。当您向该向量添加新项时,它可能会重新分配内存,这将导致所有DeviceDependent对象都被转移到向量内部的新内存块。然后将构建每个项目的新版本,并删除旧版本。施工是复制施工还是移动施工无关;无论哪种方式,对象都会有效地更改其地址。
为了使代码正确,DeviceDependent对象需要在其析构函数中注销自己,并在复制和移动构造函数中注册自己。如果您没有删除那些构造函数,那么无论您对存储的其他决定是什么,都应该这样做。否则,如果调用这些构造函数,将执行错误的操作。
列表中没有的一种方法是通过调用reserve()来防止向量重新分配,该方法将存储最大数量的项。只有当您知道DeviceDependent对象数量的合理上限时,这才是可行的。然而,您可能会发现,保留一个估计,而不是完全消除向量重新定位,这使得取消注册和重新注册的成本变得微不足道。
听起来您的目标是获得DeviceDependents的缓存一致性。您可能会发现,使用std::deque作为主存储可以避免重新分配,同时仍然提供足够的缓存一致性。或者,您可以通过编写自定义分配器或运算符new()来获得缓存一致性。
顺便说一句,听起来你的设计是由你只是猜测的性能成本驱动的。如果你真的测量它,你可能会发现使用std::vector>很好,而且不会显著减少迭代它们所需的时间。(请注意,这里不需要共享指针,因为矢量是唯一的所有者,所以可以避免引用计数的开销。)
- 将数组的地址分配给变量并删除
- C++为构建时间获取QDateTime的可靠方法
- 空基优化子对象的地址
- 从持续时间构造std::chrono::system_clock::time_point
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- while循环中while循环的时间复杂度是多少
- 使用简单类型列表实现的指数编译时间.为什么
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 在已经使用Git的情况下减少编译时间
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何将包含epoch时间的十六进制字符串转换为time_t
- 如何在c++程序中找到函数的地址
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 被解释为低级别const的const对象的地址
- 从文本文件中读取时钟时间和事件时间并进行处理
- 如何在 c++ stl 中获取列表中被推回的元素的地址,在常量时间内?
- 结构成员的地址作为编译时间常数之间的差异
- 移动语义、标准集合和构造时间地址