2

コンマ区切りの文字列を const char* のベクトルに変換しようとしています。次のコードでは、予想される出力は

ABC_
DEF
HIJ

しかし、私は得る

HIJ
DEF
HIJ

どこが間違っていますか?

コード:

#include <iostream>
#include <boost/tokenizer.hpp>
#include <vector>
#include <string>
using namespace std;

int main()
{
   string s("ABC_,DEF,HIJ");
   typedef boost::char_separator<char> char_separator;
   typedef boost::tokenizer<char_separator> tokenizer;

   char_separator comma(",");
   tokenizer token(s, comma);
   tokenizer::iterator it;

   vector<const char*> cStrings;

   for(it = token.begin(); it != token.end(); it++)
   {
      //cout << (*it).c_str() << endl;
      cStrings.push_back((*it).c_str());
   }

   std::vector<const char*>::iterator iv;
   for(iv = cStrings.begin(); iv != cStrings.end(); iv++)
   {
      cout << *iv << endl;
   }
   return 0;
}

http://ideone.com/3tvnUs

編集: 以下の回答を利用したソリューション: (PaulMcKenzie は、リストを使用してより適切なソリューションを提供しています。)

#include <iostream>
#include <boost/tokenizer.hpp>
#include <vector>
#include <string>
using namespace std;

char* createCopy(std::string s, std::size_t bufferSize)
{
   char* value = new char[bufferSize];
   memcpy(value, s.c_str(), (bufferSize - 1));
   value[bufferSize - 1] = 0;
   return value;
}

int main()
{
   string s("ABC_,DEF,HIJ");
   typedef boost::char_separator<char> char_separator;
   typedef boost::tokenizer<char_separator> tokenizer;

   char_separator comma(",");
   tokenizer token(s, comma);
   tokenizer::iterator it;

   vector<const char*> cStrings;

   for(it = token.begin(); it != token.end(); it++)
   {
      //cout << it->c_str() << endl;
      cStrings.push_back(createCopy(it->c_str(),
                                      (it->length() + 1)));
   }

   std::vector<const char*>::iterator iv;
   for(iv = cStrings.begin(); iv != cStrings.end(); iv++)
   {
      cout << *iv << endl;
   }

   //delete allocations by new
   //...
   return 0;
}
4

2 に答える 2

5

ここに問題があります:boost::tokenizer::iterator文字列のコピーの所有権を返すのではなく、内部コピーへの参照を返します。

たとえば、コードを実行した後、次のようになります。

HIJ
HIJ
HIJ

cStrings.push_back((*it).c_str())解決策は、次のいずれかに置き換えることです。

    char* c = new char[it->length() + 1];
    c[it->length()] = 0;
    cStrings.push_back(c);
    std::strncpy(c, it->c_str(), it->length());

見た目は良くありませんが、おそらくそれより速くなることはありません (少なくともboost::tokenizer.

boost::tokenizer他のオプションは、例を完全に置き換えることですstrtok- 例はここにあります: C split a char array into different variables

も使用できますが、後で に再マッピングするboost::algorithm::string::split必要がある場合があります。stringconst char*

于 2015-05-11T22:27:41.687 に答える
1

これは、動的割り当てを必要とせず、同時に探している std::vector を提供するメソッドです。秘訣は、引数を「永続的な」ストレージに作成し、ポインターのベクトルをこのストレージに設定することです。

以下のコードはstd::list、永続ストレージに使用します。その理由はstd::list、リスト コンテナーにアイテムを追加するときに、アイテムへの反復子が無効にならないことを保証できるからです。これは、 の最終的なベクトルを構築するときに必要な要件ですconst char *

#include <iostream>
#include <boost/tokenizer.hpp>
#include <vector>
#include <string>
#include <list>

typedef std::vector<char> CharArray;
typedef std::list<CharArray> StringList;

using namespace std;

int main()
{
   StringList sList;

   string s("ABC_,DEF,HIJ");
   typedef boost::char_separator<char> char_separator;
   typedef boost::tokenizer<char_separator> tokenizer;

   char_separator comma(",");
   tokenizer token(s, comma);
   tokenizer::iterator it;

   vector<const char*> cStrings;

   for(it = token.begin(); it != token.end(); ++it)
   {
        // create an array of char and place on list
        sList.push_back(CharArray(it->begin(), it->end()));

        // null terminate this entry
        sList.back().push_back(0);

        // add the pointer to this entry to the vector of const char *.
        cStrings.push_back(&sList.back()[0]);
   }

   std::vector<const char*>::iterator iv;
   for(iv = cStrings.begin(); iv != cStrings.end(); iv++)
   {
      cout << *iv << endl;
   }
}

ここでメモリを動的に割り当てる必要はないことに注意してください。確実にする必要がある唯一のことはStringList、これが引数が見つかる場所であるため、スコープ外に出ないことです。

于 2015-05-12T01:26:48.857 に答える