gpt4 book ai didi

c++ - 如何使我的 uninitialised_allocator 安全?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:54:59 31 4
gpt4 key购买 nike

来自 this question , 我想用 unitialised_allocator比如说,std::vector避免在构建时对元素进行默认初始化(或 resize()std::vector(有关用例,另请参阅 here)。我当前的设计如下所示:

// based on a design by Jared Hoberock
template<typename T, typename base_allocator >
struct uninitialised_allocator : base_allocator::template rebind<T>::other
{
// added by Walter Q: IS THIS THE CORRECT CONDITION?
static_assert(std::is_trivially_default_constructible<T>::value,
"value type must be default constructible");
// added by Walter Q: IS THIS THE CORRECT CONDITION?
static_assert(std::is_trivially_destructible<T>::value,
"value type must be default destructible");
using base_t = typename base_allocator::template rebind<T>::other;
template<typename U>
struct rebind
{
typedef uninitialised_allocator<U, base_allocator> other;
};
typename base_t::pointer allocate(typename base_t::size_type n)
{
return base_t::allocate(n);
}
// catch default construction
void construct(T*)
{
// no-op
}
// forward everything else with at least one argument to the base
template<typename Arg1, typename... Args>
void construct(T* p, Arg1 &&arg1, Args&&... args)default_
{
base_t::construct(p, std::forward<Arg1>(arg1), std::forward<Args>(args)...);
}
};

然后是unitialised_vector<>模板可以这样定义:

template<typename T, typename base_allocator = std::allocator<T>>
using uninitialised_vector =
std::vector<T,uninitialised_allocator<T,base_allocator>>;

但是,正如我的评论所指出的,我不是 100% 确定static_assert() 中的适当条件是什么(顺便说一句,人们可能会考虑 SFINAE——欢迎对此提出任何有用的意见)

显然,必须避免因尝试对未初始化的对象进行非平凡破坏而导致的灾难。考虑

unitialised_vector< std::vector<int> > x(10); // dangerous.

有人建议(Evgeny Panasyuk 的评论)我断言微不足道的可构造性,但这似乎并没有捕捉到上述灾难场景。我只是想看看 clang 对 std::is_trivially_default_constructible<std::vector<int>> 说了什么(或 std::is_trivially_destructible<std::vector<int>> )但我得到的只是 clang 3.2 的崩溃......

另一个更高级的选择是设计一个分配器,它只省略对象的默认构造,这样做是安全的。

最佳答案

首先,我认为设计可以简化,假设一个符合 C++11 的容器:

template <class T>
class no_init_allocator
{
public:
typedef T value_type;

no_init_allocator() noexcept {}
template <class U>
no_init_allocator(const no_init_allocator<U>&) noexcept {}
T* allocate(std::size_t n)
{return static_cast<T*>(::operator new(n * sizeof(T)));}
void deallocate(T* p, std::size_t) noexcept
{::operator delete(static_cast<void*>(p));}
template <class U>
void construct(U*) noexcept
{
static_assert(std::is_trivially_default_constructible<U>::value,
"This allocator can only be used with trivally default constructible types");
}
template <class U, class A0, class... Args>
void construct(U* up, A0&& a0, Args&&... args) noexcept
{
::new(up) U(std::forward<A0>(a0), std::forward<Args>(args)...);
}
};
  1. 我认为派生自另一个分配器没有什么好处。

  2. 现在您可以让 allocator_traits 处理重新绑定(bind)

  3. U 上模板化 construct 成员。如果您想将此分配器与需要分配 T 以外的内容(例如 std::list)的某些容器一起使用,这会有所帮助。

  4. static_assert 测试移动到重要的单个 construct 成员中。

您仍然可以创建使用:

template <class T>
using uninitialised_vector = std::vector<T, no_init_allocator<T>>;

这仍然无法编译:

unitialised_vector< std::vector<int> > x(10);


test.cpp:447:17: error: static_assert failed "This allocator can only be used with trivally default constructible types"
static_assert(std::is_trivially_default_constructible<U>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我认为对 is_trivially_destructible 的测试有点矫枉过正,除非您还优化了 destroy 什么都不做。但我看不到这样做的动机,因为我相信它应该在适当的时候得到优化。如果没有这样的限制,您可以:

class A
{
int data_;
public:
A() = default;
A(int d) : data_(d) {}
};

int main()
{
uninitialised_vector<A> v(10);
}

而且效果很好。但是如果你让 ~A() 变得不平凡:

    ~A() {std::cout << "~A(" << data_ << ")\n";}

然后,至少在我的系统上,你会得到一个构造错误:

test.cpp:447:17: error: static_assert failed "This allocator can only be used with trivally default constructible types"
static_assert(std::is_trivially_default_constructible<U>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

即如果 A 具有非平凡的析构函数,则它不再是平凡可构造的。

然而,即使使用非平凡的析构函数,您仍然可以:

    uninitialised_vector<A> v;
v.push_back(A());

这行得通,因为我没有过度要求一个琐碎的析构函数。执行此操作时,我得到 ~A() 按预期运行:

~A(0)
~A(0)

关于c++ - 如何使我的 uninitialised_allocator 安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15967293/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com