簡體   English   中英

std :: 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM