gpt4 book ai didi

c++ - 为什么move构造函数不通过using声明继承

转载 作者:行者123 更新时间:2023-11-30 01:05:46 25 4
gpt4 key购买 nike

在下面的代码中,虽然基类是可移动构造的,但显然没有生成派生类的移动构造函数。

#include <cstddef>
#include <memory>
#include <cstring>
#include <cassert>

template <typename T>
class unique_array : public std::unique_ptr<T[],void (*)(void*)>
{ size_t Size;
protected:
typedef std::unique_ptr<T[],void (*)(void*)> base;
unique_array(T* ptr, size_t size, void (*deleter)(void*)) noexcept : base(ptr, deleter), Size(size) {}
public:
constexpr unique_array() noexcept : base(NULL, operator delete[]), Size(0) {}
explicit unique_array(size_t size) : base(new T[size], operator delete[]), Size(size) {}
unique_array(unique_array<T>&& r) : base(move(r)), Size(r.Size) { r.Size = 0; }
void reset(size_t size = 0) { base::reset(size ? new T[size] : NULL); Size = size; }
void swap(unique_array<T>&& other) noexcept { base::swap(other); std::swap(Size, other.Size); }
size_t size() const noexcept { return Size; }
T* begin() const noexcept { return base::get(); }
T* end() const noexcept { return begin() + Size; }
T& operator[](size_t i) const { assert(i < Size); return base::operator[](i); }
unique_array<T> slice(size_t start, size_t count) const noexcept
{ assert(start + count <= Size); return unique_array<T>(begin() + start, count, [](void*){}); }
};

template <typename T>
class unique_num_array : public unique_array<T>
{ static_assert(std::is_arithmetic<T>::value, "T must be arithmetic");
public:
using unique_array<T>::unique_array;
unique_num_array(unique_num_array<T>&& r) : unique_array<T>(move(r)) {}
unique_num_array<T> slice(size_t start, size_t count) const noexcept
{ assert(start + count <= this->size()); return unique_num_array<T>(this->begin() + start, count, [](void*){}); }
public: // math operations
void clear() const { std::memset(this->begin(), 0, this->size() * sizeof(T)); }
const unique_num_array<T>& operator =(const unique_num_array<T>& r) const { assert(this->size() == r.size()); memcpy(this->begin(), r.begin(), this->size() * sizeof(T)); return *this; }
const unique_num_array<T>& operator +=(const unique_num_array<T>& r) const;
// ...
};

int main()
{ // works
unique_array<int> array1(7);
unique_array<int> part1 = array1.slice(1,3);
// does not work
unique_num_array<int> array2(7);
unique_num_array<int> part2 = array2.slice(1,3);
// test for default constructor
unique_num_array<int> array3;
return 0;
}

使用上面的代码我得到一个错误(gcc 4.8.4):

test6.cpp: In function ‘int main()’: test6.cpp:47:48: error: use of deleted function ‘unique_num_array::unique_num_array(const unique_num_array&)’ unique_num_array part2 = array2.slice(1,3);

派生类中的切片函数无法按值返回,因为缺少移动构造函数。所有其他构造函数似乎都按预期工作(本示例未涵盖)。

如果我显式定义移动构造函数(取消注释行),该示例将编译。但在这种情况下,默认构造函数消失了,这当然不是故意的。

这是怎么回事?我不明白这两种情况。

为什么在第一种情况下删除了移动构造函数?

为什么在第二种情况下会丢弃默认构造函数?其他人似乎幸存下来。

最佳答案

Why is the move constructor deleted in the first case?

因为unique_num_array<T>中有一个用户声明的复制赋值运算符,编译器没有隐式声明任何移动构造函数。 [class.copy.ctor]/8 中的标准说

If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if

  • X does not have a user-declared copy constructor,

  • X does not have a user-declared copy assignment operator,

  • X does not have a user-declared move assignment operator, and

  • X does not have a user-declared destructor.


Why is the default constructor dropped in the second case?

因为unique_num_array<T>中有一个用户声明的移动构造函数,编译器没有隐式声明默认构造函数。 [class.ctor]/4 中的标准说

... If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted ([dcl.fct.def]).


此外,由于保证 copy elision,此代码将在 C++17 之后工作.详细地说,在 C++17 之前,上下文的语义

return unique_num_array<T>(...);

unique_num_array<int> part2 = array2.slice(1,3);

需要复制/移动操作,而在 C++17 之后,语义变为目标对象由纯右值初始化器初始化,而无需具体化临时对象,因此不需要复制/移动。

关于c++ - 为什么move构造函数不通过using声明继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47968646/

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