[英]How do std::exception's derivatives pass the string from their constructor to its what() virtual function?
[英]What is the exception specification of std::function's move constructor?
我看過cppreference.com ,他們似乎沒有在std::function(std::function&&)
上指出noexcept
規范。 這對我來說似乎很奇怪。 在這種情況下,標准是否真的沒有給出保證?
引用標准(根據您的要求):
C ++11§20.8.11.2.1/ 6 (來自N3290):
function(function&& f);
template <class A> function(allocator_arg_t, const A& a, function&& f);
效果:如果!f
,*this
沒有目標; 否則,move-將f
的目標構造到*this
的目標中,使f
處於具有未指定值的有效狀態。
所以,抱歉,移動構造函數沒有noexcept
。
有一個相關的缺陷報告2062仍然是開放的,但它是朝着另一個方向發展,可以這么說,即至少有一個明顯不應該存在的noexcept
,無論其理由是什么......
可能意圖是支持具有拋出移動構造函數的可調用對象。 但這只是在合理化方向上的猜測。 例如,想象在這樣的函數對象的向量中重新分配緩沖區,其中嘗試移動原件,並且在其中一個地方拋出其中一個地方(我認為這是Abrahams et.al的原始示例) 。 哦,當然,他們不能保證會被搬回來,我們也不能前進。 因此重新分配失敗,導致重新分配的操作失敗, 向量處於無效狀態 。 對可調用對象進行非拋擲移動的要求將支持函數對象的這種一般用法,包括優化的向量重新分配(等)。 恕我直言,令人懷疑的是,真正的目的是做出這種權衡。
其他答案都沒有對我有意義。 std::function
確實有一個noexcept
默認構造函數和一個noexcept
swap
方法,因此實現者總是可以像這樣定義移動構造函數:
function(function&& other) noexcept
: function()
{
swap(*this, other);
}
考慮到上述情況,我不確定為什么委員會拒絕讓移動構造函數noexcept
。 在任何情況下,您都可以通過創建包裝來保存std::function
並使用此技術移動它來解決此問題。
我想function
對象能夠存儲任意的,用戶定義的,可調用的對象。 移動function
對象時,也會移動包含的用戶定義對象,並且無法保證可以在沒有異常的情況下完成此操作。
正如其他人所說的那樣, std::function
move構造std::function
不是 C ++標准的noexcept
。
正如Peter Ruderman說,實現者可以定義noexcept
使用移動構造函數swap
法(其noexcept
由標准)。
並且GCC實現實際上使用了這種技術並將std::function
移動構造std::function
定義為noexcept
:
/**
* @brief %Function move constructor.
* @param __x A %function object rvalue with identical call signature.
*
* The newly-created %function contains the target of @a __x
* (if it has one).
*/
function(function&& __x) noexcept : _Function_base()
{
__x.swap(*this);
}
因此,如果您使用GCC ,您可以假設std::function
移動構造函數是noexcept
。 但是C ++標准庫的其他實現可能具有移動構造函數的不同實現。 所以你不能依賴它。
最好使用std::function
default構造( noexcept
),然后使用swap
方法:
// the line below could throw
// std::function<void()> my_function(std::move(the_function_to_move_from));
// the code below is noexcept
std::function<void()> my_function;
my_function.swap(the_function_to_move_from);
它不像使用移動構造函數那樣優雅,但至少它是可移植的。
並提防移動語義! 它可能會執行您不期望的操作,因為通常會指定將對象從有效但未指定的狀態移開。 例如:
#include <iostream>
#include <functional>
struct A
{
void call()
{
if (fn) fn();
}
std::function<void()> fn;
};
int main()
{
std::function<void()> hello = []() { std::cerr << "Hello world" << std::endl; };
A a;
hello = std::move(a.fn);
a.call(); // may print "Hello world". Is it what you expect?
return 0;
}
GCC實現不會打印“Hello world” ,但其他實現可能會這樣做。 正確的方法是明確清除從中移動的對象:
hello = std::move(a.fn);
a.fn = nullptr;
但它使得移動語義不便於使用(IMO)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.