簡體   English   中英

在GCC的“Debug”版本中綁定檢查std :: array

[英]Bound checking of std::array in “Debug” version of GCC

專家解釋了編程時C ++ 11 std::array的優點,但我希望從編譯器中獲得一些東西。 能夠打開在編譯使用[]的代碼時使用.at()時默認的范圍檢查。

檢查范圍違規尤其是多維數組可能是有益的,因為在這種情況下,范圍違規不太可能導致segfault(因為你經常在內部數組周圍擁有內存,所以[5000][-123]仍然可能指向內存你擁有的)。

所以我想知道是否有一個開關可以編譯成檢查范圍的機器代碼:

    const uint32_t dim1=10*1000,dim2=3;
    std::array<std::array<int, dim2>, dim1> test_2Darray;
    int undefined_value=test_2Darray[dim2-1][dim1-1];
    std::cout<<"ouch ("<<undefined_value<<")"<<std::endl;
    int ok_value=test_2Darray[dim1-1][dim2-1];
    std::cout<<"OK   ("<<ok_value<<")"<<std::endl;
    //  test_2Darray.at(dim2-1).at(dim1-1); -->terminate called after throwing an instance of 'std::out_of_range'
    //      what():  array::at

如果你問為什么我不切換到.at() - 我可能需要性能,我也有很多代碼[]已經寫好了,我不聰明,不能聰明地替換1D更不用說2D了陣列。

我使用GCC 4.6

看起來gcc 4.6附帶的數組還沒有調試模式。 可以理解,因為C ++ 11支持仍然是實驗性的。

有一個標志_GLIBCXX_DEBUG ,通常用於打開調試模式。 如果你看一下/usr/include/c++/4.6/debug/vector:313,你會看到operator[]有:

__glibcxx_check_subscript(__n);

現在,這可能是超級邪惡(我的意思是真的很邪惡),但看起來我們可以有條件地將它添加到數組中。 更改/usr/include/c++/4.6/array的第148-154行:

reference
operator[](size_type __n)
{ return _M_instance[__n]; }

const_reference
operator[](size_type __n) const
{ return _M_instance[__n]; }

至:

reference
operator[](size_type __n)
{
#ifdef _GLIBCXX_DEBUG
    __glibcxx_check_subscript(__n);
#endif
    return _M_instance[__n];
}

const_reference
operator[](size_type __n) const
{
#ifdef _GLIBCXX_DEBUG
    __glibcxx_check_subscript(__n);
#endif
    return _M_instance[__n];
}

這意味着您可以像對向量和其他stl調試一樣啟用對數組的邊界檢查 - 通過向編譯行添加-D_GLIBCXX_DEBUG 例如:

g++ someAwesomeProgram.cpp -D_GLIBCXX_DEBUG

我只是看看gcc的樹干,顯然沒有提到但_GLIBCXX_DEBUG數組:(。 http://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/include/std/array

希望它不會太遠。 我想我們將有足夠的安全迭代器以及調試模式中的所有數組。 與此同時,這可能是我們的小秘密:-)。

template<class T, std::size_t N>
T const& at(std::array<T,N> const& arr, std::size_t pos){
#ifndef NDEBUG
  // debug versions, automatically range checked
  return arr.at(pos);
#else
  // release version, unchecked
  return arr[pos];
#endif
}    

template<class T, std::size_t N>
T& at(std::array<T,N>& arr, std::size_t pos){
  typedef std::array<T,N> const& const_array;
  // const_cast of the return is safe here because be pass a non-const array
  // const_cast for the argument is needed to avoid infinite recursion
  return const_cast<T&>(at(const_cast<const_array>(arr), pos));
}

應該做的工作。 只需at(arr, pos)整個代碼庫中使用at(arr, pos)

您可以模仿您想要的行為:

#include <array>
#include <cassert>
#include <iostream>

#ifndef NDEBUG
template <typename T, std::size_t N>
struct my_array : std::array<T,N> {
 T& operator[](std::size_t n) {
   assert(n < N);
   return (*static_cast<std::array<T,N>*>(this))[n];
 }
 const T& operator[](std::size_t n) const {
   assert(n < N);
   return (*static_cast<const std::array<T,N>*>(this))[n];
 }
};
#else
// I would use Alias templates here, but isn't supported on my compiler yet!
template <typename T, std::size_t N>
struct my_array : std::array<T,N> {
};
#endif

它與std::array不完全匹配,但如果對你很重要,可以修復它。 然后用my_array替換對std::array所有引用,你將獲得調試版本的范圍檢查operator[]

(我已經使用模板別名來簡化NDEBUG代碼,但我實際上無法在我的編譯器上測試它)

libstdc++的是gcc附帶的標准庫實現(如果你願意,可以自由使用另一個實現)。

libstdc++有一個預處理程序標志,可用於調試-D_GLIBCXX_DEBUG ,但是您應該注意,此調試模式會更改類型的ABI,因此您需要鏈接已啟用此調試模式編譯的庫。 這可能很痛苦。

libc++是另一個實現(符合C ++ 11標准),它首先針對Clang,但應該適用於任何兼容的編譯器。 它旨在維護ABI兼容性,無論是否啟用調試。 但它在OS X之外並不完全穩定(主要是因為語言環境),因此可能無法在您的環境中使用。

請注意,這兩個庫都是自由軟件,因此如果沒有實現檢查,您可以完美地提交補丁。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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