web-dev-qa-db-ja.com

反復子をポインターに変換しますか?

n要素を持つ_std::vector_があります。ここで、最後の_n-1_要素を持つベクトルへのポインターを関数に渡す必要があります。

たとえば、私の_vector<int> foo_には_(5,2,6,87,251)_が含まれます。関数は_vector<int>*_を取り、_(2,6,87,251)_へのポインターを渡します。

イテレータ++foo.begin()を(安全に)取得し、ポインタに変換して関数に渡すことはできますか?または_&foo[1]_を使用しますか?

PDATE:人々は、ポインターではなくイテレーターを使用するように関数を変更することを提案しています。私が言及した関数は_unordered_set<std::vector*>_のfind関数なので、私の状況ではそれは不可能のようです。したがって、その場合、fooから_n-1_要素を新しいベクトルにコピーし、その唯一のオプションへのポインターでfindを呼び出しますか?非常に非効率的です!特に多くのサブセット(最後の_n-1_、次に_n-2_などの要素をクエリし、_unordered_set_にあるかどうかを確認する必要があるため、これは画家のシュレミエルに似ています。

43
Frank

私が言及した関数は_unordered_set<std::vector*>_の検索関数なので、私の状況ではそれは不可能のようです。

カスタムハッシュ/述語関数オブジェクトを使用していますか?そうでない場合は、unordered_set<std::vector<int>*>::find()に、検索する正確なベクトルへのポインターを渡す必要があります。同じ内容の別のベクターへのポインターは機能しません。控えめに言っても、これは検索にはあまり役に立ちません。

_unordered_set<std::vector<int> >_を使用すると、値でルックアップを実行できるため、より適切です。 hashには_vector<int>_の専門知識がないため、カスタムハッシュ関数オブジェクトも必要になると思います。

いずれにしても、他の人が説明したように、ベクターの中央へのポインターはそれ自体がベクターではありません。内容をコピーしないと、反復子をベクターへのポインターに変換できません。

8
bk1e

ここでは、反復子useの対応するポインタへの参照を取得しています。

例:

string my_str= "hello world";

string::iterator it(my_str.begin());

char* pointer_inside_buffer=&(*it); //<--

[通知演算子*はreferenceを返すため、参照に対して&を実行するとアドレスが表示されます]。

83
Robocide

可能であれば、関数を変更して、要素への反復子または新しいベクトル(変更されていない場合)を取得することをお勧めします。

配列の格納方法を知っているので、配列でこの種のことを行うことができますが、ベクトルで同じことを行うのはおそらく悪い考えです。 &foo[1]にはタイプvector<int>*がありません。

また、STLの実装はオンラインで利用できますが、通常、抽象化の内部構造に依存しようとするのは危険です。

6
Uri

ベクターは、その要素の完全な所有権を持つコンテナーです。 1つのベクトルは、constビューであっても、別のベクトルの部分ビューを保持できません。これが根本的な原因です。

それが必要な場合は、データに対するweak_ptrのビューを持つ独自のコンテナーを作成するか、範囲を確認します。ペアのイテレーター(ポインターでさえベクターへのイテレーターとして機能します)または、さらに良いことに、かなりシームレスに機能するboost :: iterator_range。

コードのテンプレート化可能性に依存します。 cppでコードを非表示にする必要がある場合は、std :: pairを使用します。

3
Macke

あなたの関数は_vector<int>*_を取るべきではありません;必要に応じて_vector<int>::iterator_または_vector<int>::const_iterator_を取る必要があります。次に、foo.begin() + 1を渡すだけです。

3

あなたの質問に対する直接的な答えはイエスです。 fooがベクトルの場合、これを行うことができます:&foo [1]。

ただし、標準ではベクターは連続メモリを使用してストレージを実装すると言われているため、これはベクターに対してのみ機能します。

しかし、表現力が高いため、未加工のポインタの代わりにイテレータを渡すことができます(おそらくそうすべきです)。イテレータを渡しても、ベクトルのコピーは作成されません。

2
John Dibling

たとえば、vector<int> fooには(5,2,6,87,251)が含まれます。関数はvector<int>*を受け取り、(2,6,87,251)へのポインターを渡します。

vector<int>へのポインターは、ベクトルの要素へのポインターとまったく同じものではありません。

これを行うには、ポインタを渡す要素のみを含む新しいvector<int>を作成する必要があります。何かのようなもの:

 vector<int> tempVector( foo.begin()+1, foo.end());

 // now you can pass &tempVector to your function

ただし、関数がarray intへのポインターを取る場合は、&foo[1]を渡すことができます。

1
Michael Burr

つかいます - vector::front 、最もポータブルなソリューションである必要があります。 char ptrを必要とする固定APIとインターフェースをとるときにこれを使用しました。例:

void funcThatTakesCharPtr(char* start, size_t size);

...

void myFunc(vector<char>& myVec)
{
    // Get a pointer to the front element of my vector:
    char* myDataPtr = &(myVec.front());

    // Pass that pointer to my external API:
    funcThatTakesCharPtr(myDataPtr, myVec.size());
}
1
Ogre Psalm33

イテレーターをポインターに変換する安全なバージョン(意味に関係なく正確に何を意味するか)と安全で、イテレーターを逆参照し、end()/otherに起因する可能性のある例外/エラーを引き起こす心配がない状況

#include <iostream>
#include <vector>
#include <string.h>

int main()
{
    std::vector<int> vec;

    char itPtr[25];
    long long itPtrDec;

    std::vector<int>::iterator it = vec.begin();
    memset(&itPtr, 0, 25);
    sprintf(itPtr, "%llu", it);
    itPtrDec = atoll(itPtr);
    printf("it = 0x%X\n", itPtrDec);

    vec.Push_back(123);
    it = vec.begin();
    memset(&itPtr, 0, 25);
    sprintf(itPtr, "%llu", it);
    itPtrDec = atoll(itPtr);
    printf("it = 0x%X\n", itPtrDec);
}

のようなものを印刷します

it = 0x0

it = 0x2202E10

それは信じられないほどハック的な方法ですが、必要な場合は仕事をします。コンパイラの警告が表示されますが、本当に気になる場合は、#pragmaで削除できます

0
Shocker

私はこれをテストしていませんが、代わりにイテレーターのペアのセットを使用できますか?各反復子ペアは、シーケンスベクトルの開始反復子と終了反復子を表します。例えば。:

typedef std::vector<int> Seq;
typedef std::pair<Seq::const_iterator, Seq::const_iterator> SeqRange;

bool operator< (const SeqRange& lhs, const SeqRange& rhs)
{
    Seq::const_iterator lhsNext = lhs.first;
    Seq::const_iterator rhsNext = rhs.first;

    while (lhsNext != lhs.second && rhsNext != rhs.second)
        if (*lhsNext < *rhsNext)
            return true;
        else if (*lhsNext > *rhsNext)
            return false;

    return false;
}

typedef std::set<SeqRange, std::less<SeqRange> > SeqSet;

Seq sequences;

void test (const SeqSet& seqSet, const SeqRange& seq)
{
    bool find = seqSet.find (seq) != seqSet.end ();
    bool find2 = seqSet.find (SeqRange (seq.first + 1, seq.second)) != seqSet.end ();
}

明らかに、ベクターは以前のように他の場所に保持する必要があります。また、シーケンスベクトルが変更された場合、イテレータが変更された可能性があるため、セット内のエントリを削除して再追加する必要があります。

ジョン

0
jon-hanson

関数が本当にvector<int> *(ベクターへのポインター)をとる場合、&fooを渡す必要があります。これはベクターへのポインターになるためです。明らかにそれは単にあなたの問題を解決するものではありませんが、イテレータのアドレスにあるメモリは有効なベクトルを直接アドレスしないので、イテレータを直接ベクトルに変換することはできません。

vector constructor :を呼び出すことで、新しいベクターを作成できます。

template <class InputIterator> vector(InputIterator, InputIterator)

これは、2つの反復子の間で要素をコピーすることにより、新しいベクトルを構築します。おおよそ次のように使用します。

bar(std::vector<int>(foo.begin()+1, foo.end());
0

ベクターはテンプレートクラスであり、クラスの内容をポインターに変換することは安全ではありません。ベクタークラスを継承してこの新しい機能を追加することはできません。また、関数パラメーターを変更することは、実際には良いアイデアです。 Jstは、intベクトルtemp_foo(foo.begin [X]、foo.end())の別のベクトルを作成します。このベクトルを関数に渡します

0
vivek sapru