3

十分なメモリを備えた 64 ビット Linux ボックスで実行しているにもかかわらず、stringstream の 4GB 制限を超えることができません。

以下のテスト コード (コメントを読んで修正) は、4GB 後のコア ダンプです。

gdb トレースから、stringstream はデフォルトの std::char_traits を使用します。この場合、int_type は 64 ビットの size_t ではなく 32 ビットの int に設定されます。回避策はありますか?

#include <stdint.h>
#include <iostream>
#include <sstream>
#include <math.h>
using namespace std;

int main(int narg, char** argv)
{
    string str;
    stringstream ss;
    const size_t GB = (size_t)pow(2, 30);

    str.resize(GB, '1');
    cerr << "1GB=" << str.size()
             << ", string::max_size=" << str.max_size()/GB << "GB"
             << ", sizeof(int)=" << sizeof(int)
             << ", sizeof(int64_t)=" << sizeof(int64_t)
             << ", sizeof(size_t)=" << sizeof(size_t)
             << endl;
    string().swap(str);

    str.resize(6*GB, '6');
    cerr << "str.size()=" << (str.size() / GB) << "GB allocated successfully"
            << ", ended with " << str.substr(str.size()-5, 5) << endl;
    string().swap(str);

    str.resize(GB/4, 'Q');
    cerr << "writing to stringstream..." << std::flush;
    for (int i = 0; i < 30; ++i) {
        ss << str << endl;
        cerr << double(ss.str().size())/GB << "GB " << std::flush;
    }
    cerr << endl;
    exit(0);
}

出力は次のとおりです。

1GB=1073741824, string::max_size=4294967295GB, sizeof(int)=4, sizeof(int64_t)=8, sizeof(size_t)=8
str.size()=6GB allocated successfully, ended with 66666
writing to stringstream...0.25GB 0.5GB 0.75GB 1GB 1.25GB 1.5GB 1.75GB 2GB 2.25GB 2.5GB 2.75GB 3GB 3.25GB 3.5GB 3.75GB Segmentation fault (core dumped)

gdb スタック トレースは次のとおりです。

(gdb) where
#0  0x00002aaaaad5e0c1 in std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow(int) () from /usr/lib64/libstdc++.so.6
#1  0x00002aaaaad62cbd in std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, long) () from /usr/lib64/libstdc++.so.6
#2  0x00002aaaaad5657d in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) () from /usr/lib64/libstdc++.so.6
#3  0x000000000040112b in main ()

バイナリは64ビットのようです。

$ file a.out
a.out: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, not stripped

ニック、プリプロセッサの出力をチェックするのは良い点です。どういうわけか、std::char_straits は __gnu_cxx::char_straits を上書きし、int_type を __gnu_cxx::char_straits のような unsigned long ではなく int に再定義します。これは非常に驚くべきことです。

namespace __gnu_cxx
{
# 61 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3
  template <class _CharT>
    struct _Char_types
    {
      typedef unsigned long int_type;
      typedef std::streampos pos_type;
      typedef std::streamoff off_type;
      typedef std::mbstate_t state_type;
    };
# 86 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3
  template<typename _CharT>
    struct char_traits
    {
      typedef _CharT char_type;
      typedef typename _Char_types<_CharT>::int_type int_type;
      typedef typename _Char_types<_CharT>::pos_type pos_type;
      typedef typename _Char_types<_CharT>::off_type off_type;
      typedef typename _Char_types<_CharT>::state_type state_type;
              ....
               };

namespace std
{
# 224 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3
  template<class _CharT>
    struct char_traits : public __gnu_cxx::char_traits<_CharT>
    { };



  template<>
    struct char_traits<char>
    {
      typedef char char_type;
      typedef int int_type;
      typedef streampos pos_type;
      typedef streamoff off_type;
      typedef mbstate_t state_type;
              ...
              };

編集: 以下、STL Web サイトhttp://www.cplusplus.com/reference/string/char_traits/から。char_traits の特殊化では int が使用されます。

typedef INT_T int_type; 
Where INT_T is a type that can represent all the valid characters representable by a    char_type plus an end-of-file value (eof) which is compatible with iostream class member functions.
For char_traits<char> this is int, and for char_traits<wchar_t> this is wint_t 
4

1 に答える 1

1

前処理されたソース ファイルを投稿できますか。

への参照_Char_typesは誤解を招くため削除されました。

int_type が関連しているかどうかはわかりませんが、char の特殊化では実際に int_type に int が使用されます。

int_type は、個々の文字を保持するための typedef です (つまり、ascii の場合は少なくとも 1 バイト、wchar_t の場合はそれ以上)。文字の範囲を格納するためには使用されません (以下の std::streamoff を参照)。


前処理された出力から、 std::streamoff が原因であると思われます。私のシステムのヘッダーから:

# 90 "/usr/include/c++/4.6/bits/postypes.h" 3
  typedef long streamoff;

std::streamoff は std::streampos で使用されます。これが間違って定義されていると、文字列ストリームがオーバーフロー関数を呼び出すことにつながると思います。

正しいヘッダーが含まれていることを確認しましたか?

# 61 "/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/char_traits.h" 3

次のパスです:

/usr/include/c++/4.1.2/bits/char_traits.h

-ニック

于 2012-08-29T04:07:14.600 に答える