2013-01-13 34 views
2

我想創建一個帶有變量引用的boost融合向量。目標是將函數傳遞給函數,並將它們添加到融合向量中。由於引用類型,我使用TMP每次添加一個元素。但是有時融合向量中的某些元素是錯誤的。這看起來像未定義的行爲(錯誤的值,讀取訪問衝突)。
我寫了一個例子,其中我展開了在TMP中使用的遞歸以便於理解。它只是兩個引用添加到融合載體,並輸出結果:添加對boost :: fusion :: vector的引用

#include <iostream> 

#include <boost/ref.hpp> 
#include <boost/fusion/algorithm.hpp> 
#include <boost/fusion/container.hpp> 

using namespace boost; 
using namespace boost::fusion; 

//add second element 
template <typename T> 
vector<int&, double&> createVector2(T vec, double& v2) { 
    auto newVector = join(vec, make_vector(ref(v2))); 
    return newVector; 
} 

//add first element 
template <typename T> 
vector<int&, double&> createVector(T vec, int& v1, double& v2) { 
    auto newVector = join(vec, make_vector(ref(v1))); 
    return createVector2(newVector, v2); 
} 

int main() { 
    int v1 = 10; 
    double v2 = 15.3; 

    vector<> vec; 
    auto ret = createVector(vec, v1, v2); 

    std::cout << at_c<0>(ret) << std::endl; 
    std::cout << at_c<1>(ret) << std::endl; 

    if (at_c<0>(ret) != v1) { 
     std::cout << "FAILED" << std::endl; 
    } 

    if (at_c<1>(ret) != v2) { 
     std::cout << "FAILED" << std::endl; 
    } 

    return 0; 
} 

程序崩潰,當在升壓融合載體的引用被訪問(讀取訪問衝突),首先在這一行:

std::cout << at_c<0>(ret) << std::endl; 

我使用VC11作爲編譯器(版本17.00.51106.1)。該錯誤僅在發佈模式下。但是當我使用VC10,GCC 4.7.0或GCC 4.7.2時,沒有錯誤,程序工作得很好。
要獲得VC11的工作方案,我有這條線

auto newVector = join(vec, make_vector(ref(v1))); 

改變

auto newVector = as_vector(join(vec, make_vector(ref(v1)))); 

因此,沒有上面的例子中存在一個bug或者是有什麼不對的VC11優化?它允許傳遞一個本地boost視圖(boost :: fusion :: join只返回一個視圖,並且視圖被boost :: fusion :: vector轉換爲一個'normal'boost :: fusion :: vector)到另一個視圖函數的價值?

回答

1

我在Microsoft connect(link)上提交了一個錯誤報告。所以我的問題的答案是我的代碼中有一個錯誤。

問題是,連接函數返回一個boost融合joint_view,它包含兩個元素seq1和seq2。它們被定義爲:

template <typename Sequence1, typename Sequence2> 
struct joint_view : sequence_base<joint_view<Sequence1, Sequence2> > 
{ 
    (...) 
private: 
    typename mpl::if_<traits::is_view<Sequence1>, Sequence1, Sequence1&>::type seq1; 
    typename mpl::if_<traits::is_view<Sequence2>, Sequence2, Sequence2&>::type seq2; 
}; 

我的代碼的問題是,我將一個臨時對象(從make_vector返回)傳遞給連接函數。增強融合向量不是視圖,seq1和seq2是引用。所以join函數返回一個包含對臨時對象的引用的joint_view,它是無效的。有兩個修改來解決這個:

  1. 第一溶液(同爲createVector):

    template <typename T> 
    vector<int&, double&> createVector2(T vec, double& v2) { 
        auto x = make_vector(ref(v2)); 
        auto newVector = join(vec, x); 
        return newVector; 
    } 
    

    現在加入返回包含一個參考X,這是無效的joint_view。最後,視圖被轉換爲增強融合矢量,並且引用被解析。

  2. 第二溶液(同樣爲createVector):

    template <typename T> 
    vector<int&, double&> createVector2(T vec, double& v2) { 
        return join(vec, make_vector(ref(v2))); 
    } 
    

    的臨時對象(由make_vector返回)的壽命是整個return語句和在第一個版本,視圖將被轉換爲一個增強融合向量,並再次解決引用。

感謝Eric Brumer(微軟)提供了這兩種解決方案。

結論: 不要將臨時對象傳遞給boost融合連接函數(僅當它是另一個視圖時)。

相關問題