- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
假设您有一个 Container,它在内部使用其他标准容器来形成更复杂的数据结构。值得庆幸的是,标准容器已经被设计为完成所有必要的工作,以确保分配器被复制/分配等。
所以,通常如果我们有一些容器 c
,并且在内部它有一个 std::vector<int>
,我们可以写一个复制赋值运算符,它只是说:
Container& operator = (const Container& c) { m_vec = c.m_vec; return *this; }
Container& operator = (const Container& c)
{
/* some other stuff... */
m_vec = c.m_vec;
return *this;
}
std::vector<node*, Alloc>
Container& operator = (const Container& other)
{
vector<node*, Alloc>::allocator_type alloc = m_vec.get_allocator();
for (auto it = m_vec.begin(); it != m_vec.end(); ++it) alloc.deallocate(*it);
m_vec.clear();
for (auto it = other.m_vec.begin(); it != other.m_vec.end(); ++it)
{
node* n = alloc.allocate(1); // this is wrong, we might need to use other.get_allocator() here!
alloc.construct(n, *(*it));
m_vec.push_back(n);
}
return *this;
}
node
m_vec
中的对象,然后从 RHS 容器构造新的节点对象。 (请注意,我使用的分配器对象与 vector 在内部使用的分配器对象相同,以便分配节点对象。)
allocator_traits<std::vector<node*, Alloc>::allocator_type>
套
propagate_on_container_copy_assign
为真。如果是,我们需要使用另一个容器的分配器来构造复制的节点。
Container
不使用它自己的分配器。它只使用内部
std::vector
...那么我们如何告诉我们的内部
std::vector
必要时使用复制分配器的实例?该 vector 没有类似“use_allocator”或“set_allocator”成员函数。
if (std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value)
{
m_vec = std::vector<node*, Alloc>(other.get_allocator());
}
m_vec.get_allocator();
构造我们的节点
最佳答案
使用 swap
的一个问题在这个例子中实现复制赋值是如果propagate_on_assignment == true_type
和 propagate_on_container_swap == false_type
,则分配器不会从 other
传播至 *this
,因为 swap
拒绝这样做。
这种方法的第二个问题是,如果 propagate_on_assignment
和 propagate_on_container_swap == true_type
但是 other.m_vec.get_allocator() != m_vec.get_allocator()
,然后您确实传播了分配器,但在 swap
处得到了未定义的行为.
要做到这一点,您真的需要设计您的 operator=
从第一任校长。对于这个练习,我假设 Container
看起来像这样:
template <class T, class Alloc>
struct Container
{
using value_type = T;
static_assert(std::is_same<typename Alloc::value_type, value_type>{}, "");
using allocator_type = Alloc;
struct node {};
using NodePtr = typename std::pointer_traits<
typename std::allocator_traits<allocator_type>::pointer>::template
rebind<node>;
using NodePtrAlloc = typename std::allocator_traits<allocator_type>::template
rebind_alloc<NodePtr>;
std::vector<NodePtr, NodePtrAlloc> m_vec;
// ...
Container
模板位于
T
和
Alloc
,并且实现允许
Alloc
的可能性正在使用“花式指针”(即
node*
实际上是一个类类型)。
Container
复制赋值运算符可能如下所示:
Container&
operator = (const Container& other)
{
if (this != &other)
{
using NodeAlloc = typename std::allocator_traits<NodePtrAlloc>::template
rebind_alloc<node>;
using NodeTraits = std::allocator_traits<NodeAlloc>;
NodeAlloc alloc = m_vec.get_allocator();
for (auto node_ptr : m_vec)
{
NodeTraits::destroy(alloc, std::addressof(*node_ptr));
NodeTraits::deallocate(alloc, node_ptr, 1);
}
if (typename NodeTraits::propagate_on_container_copy_assignment{})
m_vec = other.m_vec;
m_vec.clear();
m_vec.reserve(other.m_vec.size());
NodeAlloc alloc2 = m_vec.get_allocator();
for (auto node_ptr : other.m_vec)
{
using deleter = allocator_deleter<NodeAlloc>;
deleter hold{alloc2, 1};
std::unique_ptr<node, deleter&> n{NodeTraits::allocate(alloc2, 1),
hold};
NodeTraits::construct(alloc2, std::addressof(*n), *node_ptr);
hold.constructed = true;
m_vec.push_back(n.get());
n.release();
}
}
return *this;
}
std::allocator_traits
创建一个“
allocator<node>
”。这被命名为
NodeAlloc
在上面的例子中。为这个分配器形成特征也很方便,称为
NodeTraits
以上。
allocator<node*>
转换为
allocator<node>
),并使用该分配器来销毁和解除分配 lhs 节点。
std::addressof
需要将可能的“花式指针”转换为实际
node*
在调用
destroy
.
m_vec.get_allocator()
至
m_vec
,但前提是
propagate_on_container_copy_assignment
是真的。
vector
的复制赋值运算符是最好的方法。这不必要地复制了一些
NodePtr
s,但是我仍然相信这是传播该分配器的最佳方式。如果
propagate_on_container_copy_assignment
,我们也可以进行 vector 分配为假,从而避免了 if 语句。如果
propagate_on_container_copy_assignment
,分配将不会传播分配器是假的,但是我们仍然可以分配一些
NodePtr
s,当我们真正需要的是一个空操作。
propagate_on_container_copy_assignment
为真,并且两个分配器不相等,
vector
复制赋值运算符将在分配分配器之前为我们正确处理转储 lhs 资源。这是一个很容易被忽视的并发症,因此最好留给
vector
复制赋值运算符。
propagate_on_container_copy_assignment
是假的,这意味着我们不需要担心分配器不相等的情况。我们不会交换任何资源。
clear()
lhs。此操作不会转储
capacity()
所以不浪费。在这一点上,我们有一个带有正确分配器的零大小的 lhs,甚至可能还有一些非零
capacity()
和玩。
reserve
与
other.size()
,以防 lhs 容量不足。这条线不是正确性所必需的。这是一个纯粹的优化。
m_vec.get_allocator()
现在可能会返回一个新的分配器,我们继续获取它的新拷贝,名为
alloc2
以上。
alloc2
分配、构造和存储从 rhs 复制构造的新节点。
push_back()
也可以。 . RAII 设备必须知道它是否需要在异常情况下只解除分配,或同时销毁和解除分配。 RAII 设备还需要“花式指针”感知。事实证明,使用
std::unique_ptr
构建所有这些非常容易。结合自定义删除器:
template <class Alloc>
class allocator_deleter
{
using traits = std::allocator_traits<Alloc>;
public:
using pointer = typename traits::pointer;
using size_type = typename traits::size_type;
private:
Alloc& alloc_;
size_type s_;
public:
bool constructed = false;
allocator_deleter(Alloc& a, size_type s) noexcept
: alloc_(a)
, s_(s)
{}
void
operator()(pointer p) noexcept
{
if (constructed)
traits::destroy(alloc_, std::addressof(*p));
traits::deallocate(alloc_, p, s_);
}
};
std::allocator_traits
的一致使用用于对分配器的所有访问。这允许
std::allocator_traits
提供默认值,以便
Alloc
的作者不需要提供它们。例如
std::allocator_traits
可以为
construct
提供默认实现,
destroy
, 和
propagate_on_container_copy_assignment
.
NodePtr
的假设。是
node*
.
关于c++ - 在没有分配器的情况下在容器中遵守传播_on_copy_assignment 的习语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27494945/
如果有人能解释这个注释的作用以及我们何时使用它: @Transactional(propagation=Propagation.REQUIRED) 谢谢 最佳答案 如果您需要在 Spring Docs
我有一个页面,它有一个 keydown 事件监听器,用于监听 Escape 键,以便返回。我还有一个简单的模态类,它也监听 Escape 键以关闭它。主页监听器检查模式是否打开,如果打开,则不执行任何
我想在模型中设置默认变量名称 T (=xx) - 将该模型拖到新模型中并在其中定义变量 xx。我收到错误消息:使用未声明的变量 xx。 这是子模型 model test parameter Rea
在 android 2.x 浏览器中查看此示例..它是在我的应用程序中复制场景的示例.. http://johnchacko.net/samples/tap.html 它是关于监听“tap”并从监听器
如您所见,我正在尝试将 GatewayConnectionFailedException 传播到我的 UI。我希望此代码捕获除异常之外的所有内容,我希望表示层捕获该异常以通知用户数据库是问题所在,以便
我目前正在尝试让可执行文件与它需要的所有依赖项正确链接。 这是依赖项的示例结构: exe -> libA -> libB exe和 libA有自己的存储库。 exe拉入libA像这样的东西: add_
有什么方法可以调用带有单个参数的 Scala 函数,给定一个数组 (类似于 JavaScript Spreads在 ECMAScript 6) 中? ys = [10.0, 2.72, -3.14]
我有一个小型静态库,它需要 boost 头文件,并且需要包含目录中的“include”目录。 ... add_library(alib STATIC ...) target_include_direc
我有一些 promise 可以返回对象。 现在我想将它们合并/扩展为一个新对象,因此我使用 Lodash's extend . var whenEverythingIsDone = Promise.a
这是我认为人们通常希望在 Scala 中做的事情,但如果我能在任何地方找到一个例子,我就该死了。 这段代码由于类型删除而无法编译,但它演示了我正在努力完成的事情: def parse[T](json:
这是我认为人们通常希望在 Scala 中做的事情,但如果我能在任何地方找到一个例子,我就该死了。 这段代码由于类型删除而无法编译,但它演示了我正在努力完成的事情: def parse[T](json:
我们有大量 MOSS 2007 站点需要添加大量的 javascript。我编辑、 checkin 、发布并批准了对 default.master 的更改,更改反射(reflect)在根网站上,但没有
请看一下下面的 fiddle :http://jsfiddle.net/K9NjY/ 我在这段代码上花了 3-4 个小时,并将其缩小到最短的版本,但现在我陷入了困境。 问题:1. 点击“divOne”
我读到如果在流程中抛出异常,框架要做的第一件事就是检查消息头中的错误 channel 属性。总是这样吗? 在我的特殊情况下,我将自定义错误 channel 分配给消息 header ,但该消息似乎已向
创建一个小的 C++ 大型精度类,一切似乎都运行良好,但是添加,如果我将 0xffffffff 和 0x04 加在一起,我会得到 0xffff0003,而我应该得到 0x0100000003。这是有问
我正在尝试重新创建 Dan Abramov 类(class)中的 Redux 示例。传播{...store.getState()}在应用程序级别不起作用,Redux 正在更改状态并且 React 不会
考虑一个需要很长时间的事务。在此期间,我想对 TableSmall 执行一些小更新。 ,它应该立即执行,并且主事务的回滚不应该回滚那些小的更新。 我当前的问题是这些小更新将锁定 TableSmall\
我需要对现有函数进行修改,具有一些 const 输入参数: int f(const owntype *r1, const owntype *r2) 为了做到这一点,我想调用一个使用相同类型但没有 co
我有一个带有 ViewModel 的 WPF UserControl: 这个 UserControl 有一个 De
我试图在收到这样的短信时不传播 public class SMSReceiver extends BroadcastReceiver { @Override public void onRec
我是一名优秀的程序员,十分优秀!