gpt4 book ai didi

c++ - 对分配器感知类调用复制构造函数中的 vector 元素的引用

转载 作者:太空狗 更新时间:2023-10-29 22:56:38 25 4
gpt4 key购买 nike

我有一个包含 vector vector 的类。它是分配器感知的。当尝试调用 operator[] 将元素存储在引用中时,Visual Studio 2015 无法编译,AppleClang(最新)可以正常运行。

我不确定这是否是错误,哪个编译器是正确的,或者我的代码中是否存在某些未定义的行为。

这里是一个简洁的例子,一切都尽可能简单。

#include <cstdlib>
#include <memory>
#include <new>
#include <vector>

/* Allocator */
template <class T>
struct my_allocator {
typedef T value_type;
my_allocator() = default;

template <class U>
constexpr my_allocator(const my_allocator<U>&) noexcept {
}

T* allocate(std::size_t n) {
if (n > std::size_t(-1) / sizeof(T))
throw std::bad_alloc();
if (auto p = static_cast<T*>(std::malloc(n * sizeof(T))))
return p;
throw std::bad_alloc();
}

void deallocate(T* p, std::size_t) noexcept {
std::free(p);
}
};

template <class T, class U>
bool operator==(const my_allocator<T>&, const my_allocator<U>&) {
return true;
}
template <class T, class U>
bool operator!=(const my_allocator<T>&, const my_allocator<U>&) {
return false;
}

/* Example Element */
struct X {
X() = default;
X(X&&) = default;
X& operator=(X&&) = default;

X(const X&) = delete;
X& operator=(const X&) = delete;

int test = 42;
};

/* Example Container Class */
template <class T, class Allocator = std::allocator<T>>
struct vec_of_vec {
using OuterAlloc = typename std::allocator_traits<
Allocator>::template rebind_alloc<std::vector<T, Allocator>>;

vec_of_vec(const Allocator& alloc = Allocator{})
: data(10, std::vector<T, Allocator>{ alloc },
OuterAlloc{ alloc }) {

for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}

std::vector<T, Allocator>& operator[](size_t i) {
return data[i];
}

std::vector<std::vector<T, Allocator>, OuterAlloc> data;
};

/* Trigger Error */
int main(int, char**) {
my_allocator<X> alloc;
vec_of_vec<X, my_allocator<X>> test(alloc);

X& ref_test = test[0][0]; // <-- Error Here!
printf("%d\n", ref_test.test);

return 0;
}

VS 尝试使用 X 的复制构造函数。

error C2280: 'X::X(const X &)': attempting to reference a deleted function

function main.cpp(42): note: see declaration of 'X::X'

我在使用分配器和 allocator_traits 时缺少什么吗?

最佳答案

GCC 错误揭示了正在发生的事情,在 VS2015 案例中可能相同。

In file included from memory:65,
from prog.cc:2:
bits/stl_uninitialized.h: In instantiation of '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = __gnu_cxx::__normal_iterator<const X*, std::vector<X, my_allocator<X> > >; _ForwardIterator = X*; _Allocator = my_allocator<X>]':
bits/stl_vector.h:454:31: required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = X; _Alloc = my_allocator<X>]'
bits/alloc_traits.h:250:4: required from 'static std::_Require<std::__and_<std::__not_<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type>, std::is_constructible<_Tp, _Args ...> > > std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::vector<X, my_allocator<X> >; _Args = {const std::vector<X, my_allocator<X> >&}; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::_Require<std::__and_<std::__not_<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type>, std::is_constructible<_Tp, _Args ...> > > = void]'
bits/alloc_traits.h:344:16: required from 'static decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = std::vector<X, my_allocator<X> >; _Args = {const std::vector<X, my_allocator<X> >&}; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = void]'
bits/stl_uninitialized.h:351:25: required from '_ForwardIterator std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, _Allocator&) [with _ForwardIterator = std::vector<X, my_allocator<X> >*; _Size = long unsigned int; _Tp = std::vector<X, my_allocator<X> >; _Allocator = my_allocator<std::vector<X, my_allocator<X> > >]'
bits/stl_vector.h:1466:33: required from 'void std::vector<_Tp, _Alloc>::_M_fill_initialize(std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = std::vector<X, my_allocator<X> >; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::vector<X, my_allocator<X> >]'
bits/stl_vector.h:421:9: required from 'std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = std::vector<X, my_allocator<X> >; _Alloc = my_allocator<std::vector<X, my_allocator<X> > >; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = std::vector<X, my_allocator<X> >; std::vector<_Tp, _Alloc>::allocator_type = my_allocator<std::vector<X, my_allocator<X> > >]'
prog.cc:59:42: required from 'vec_of_vec<T, Allocator>::vec_of_vec(const Allocator&) [with T = X; Allocator = my_allocator<X>]'
prog.cc:76:46: required from here
bits/stl_uninitialized.h:275:25: error: no matching function for call to '__gnu_cxx::__alloc_traits<my_allocator<X>, X>::construct(my_allocator<X>&, X*, const X&)'
__traits::construct(__alloc, std::__addressof(*__cur), *__first);```

Wandbox

如果我们从下往上看,我们会看到:

  • vec_of_vec build 者
  • fill荷兰国际集团vector<vector>通过10份空内载体
  • 制作拷贝

尽管内部 vector 是空的,但它的复制构造函数要求它包含的类型是可复制构造的。

附言

我不知道 clang 是如何克服这个问题的。它可能认识到 vector<vector>如果填充了默认值(如果带有传递的分配器实例的构造函数仍然符合默认值),那么使用默认构造而不是复制

编辑:

修复错误替换

vec_of_vec(const Allocator& alloc = Allocator{})
: data(10, std::vector<T, Allocator>{ alloc },
OuterAlloc{ alloc }) {

for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}

通过

vec_of_vec(const Allocator& alloc = Allocator{})
{
data.resize(10); // here we don't `fill` it by copies but default-construct 10 instances
for (int i = 0; i < 10; ++i) {
data[i].resize(42);
}
}

或有状态分配器的版本:

vec_of_vec(const Allocator& alloc = Allocator{}):
data(OuterAlloc(alloc))
{
for (int i = 0; i < 10; ++i) {
data.emplace_back(alloc);
data.back().resize(42);
}
}

关于c++ - 对分配器感知类调用复制构造函数中的 vector 元素的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47318721/

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