gpt4 book ai didi

c++ - move 哪个 throw ?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:11:12 26 4
gpt4 key购买 nike

据我了解, move 构造函数和 move 赋值必须标记为 noexcept,以便编译器在例如在 vector 内部重新分配时使用它们。

但是,是否存在 move 分配、 move 构造可能实际抛出的真实案例?

更新:

例如,在构造时具有分配资源的类不能是不可抛出的。

最佳答案

However, is there any real-world case where a move-assign, move-construct (or swap) might actually throw?

是的。考虑 std::list 的实现. end迭代器必须指向列表中的“最后一个元素”。存在 std::list 的实现哪里什么end指向的是一个动态分配的节点。即使是默认构造函数也会分配这样一个节点,以便在您调用 end() 时, 有一点可以指出。

在这样的实现中,每个 构造函数都必须为end() 分配一个节点。指向……甚至 move 构造函数。该分配可能会失败,并引发异常。

同样的行为可以扩展到任何基于节点的容器。

这些基于节点的容器的实现也进行了“短字符串”优化:它们将结束节点嵌入容器类本身,而不是动态分配。因此默认构造函数(和 move 构造函数)不需要分配任何东西。

move 赋值运算符可以抛出任何 container<X>如果是容器的分配器 propagate_on_container_move_assignment::value为 false,并且如果 lhs 中的分配器不等于 rhs 中的分配器。在那种情况下, move 赋值运算符被禁止将内存所有权从 rhs 转移到 lhs。如果您使用 std::allocator,则不会发生这种情况,作为 std::allocator 的所有实例彼此相等。

更新

这是一个符合条件且可移植的示例,说明了 propagate_on_container_move_assignment::value 时的情况。是假的。它已经针对最新版本的 VS、gcc 和 clang 进行了测试。

#include <cassert>
#include <cstddef>
#include <iostream>
#include <vector>

template <class T>
class allocator
{
int id_;
public:
using value_type = T;

allocator(int id) noexcept : id_(id) {}
template <class U> allocator(allocator<U> const& u) noexcept : id_(u.id_) {}

value_type*
allocate(std::size_t n)
{
return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
}

void
deallocate(value_type* p, std::size_t) noexcept
{
::operator delete(p);
}

template <class U, class V>
friend
bool
operator==(allocator<U> const& x, allocator<V> const& y) noexcept
{
return x.id_ == y.id_;
}
};

template <class T, class U>
bool
operator!=(allocator<T> const& x, allocator<U> const& y) noexcept
{
return !(x == y);
}

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

struct A
{
static bool time_to_throw;

A() = default;
A(const A&) {if (time_to_throw) throw 1;}
A& operator=(const A&) {if (time_to_throw) throw 1; return *this;}
};

bool A::time_to_throw = false;

int
main()
{
vector<A> v1(5, A{}, allocator<A>{1});
vector<A> v2(allocator<A>{2});
v2 = std::move(v1);
try
{
A::time_to_throw = true;
v1 = std::move(v2);
assert(false);
}
catch (int i)
{
std::cout << i << '\n';
}
}

这个程序输出:

1

表示vector<T, A> move 赋值运算符在 propagate_on_container_move_assignment::value 时复制/move 其元素是 false 并且两个有问题的分配器不比较相等。如果这些拷贝/move 中的任何一个抛出,则容器 move 分配抛出。

关于c++ - move 哪个 throw ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19833258/

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