2017-01-31 8 views
2

C++配列でイテレータを使用したいが、生ポインタも使用したい。 私は、静的なベクターを用いて行うことができます。stl :: rawポインタ付きイテレータ

#define SIZE 10 
int vect[SIZE] = {0}; 
vect[3] = 5; 
int* p = std::find(std::begin(vect), std::end(vect), 5); 
bool success = p != std::end(vect); 

はどのように生のポインタ(多分ヒープが割り当てられたベクトル)でそれを行うことが可能になることができますか? もちろんコンパイラは、データのサイズを知らないので、このコード

int* pStart = vect; 
std::find(std::begin(pStart), std::end(pStart), 5); 

error C2784: '_Ty *std::begin(_Ty (&)[_Size])' : 
could not deduce template argument for '_Ty (&)[_Size]' from 'int *' 

を与えることのbegin()end()に認識させることが可能ですか?ここで

+2

どのように_what_を行うことができますか?あなたは何を達成しようとしていますか?あなたの目標は何ですか? –

+2

代わりに 'std :: array'を使います。これはC配列のすべての機能を持ちますが、実際にはSTLインタフェースを持っています。そしてイテレータはポインタとして実装されています。 – rlbond

+0

@rlbondこの場合を除いて、プレーンな配列は完全に素晴らしいです。 – juanchopanza

答えて

4

んが、ポインタにstd::beginstd::endを使用することはできません。サイズが型の一部である配列とは異なり、ポインタはポインタが指しているもののサイズを保持しません。ポインタであなたのケースでは、このかかわらずを回避する方法は、あなたがszieは、コ​​ンパイル時にどうなるか知っているつもりはないされている場合std::vectorを使用することです

std::find(pStart, pStart + SIZE, 5); 

を使用しなければならないでしょう。それはあなたのためのメモリを管理し、beginendメンバ関数を提供します。

+0

'std :: vector'を使用すると、データのコピーを含むように見えます。この場合、 'std :: find(pStart、pStart + SIZE、5);'を使用すると問題ありません。 –

+0

@Stefano私は、あなたが 'std :: vector'を使うべきである実行時のサイズを使用していると言っています。もしそうでなければ、生の配列を使うこともできますし、 'std :: array'を使うこともできます。 – NathanOliver

+0

私はC++配列を使用しています。データは共有メモリからのものであり、配列のサイズは一種の共有メモリマネージャによって動的に割り当てられるからです。 –

2

std::begin(pStart), std::end(pStart) 

あなたはポインタの始まりと終わりを取るしようとしています。いいえ!

代わりに、あなたは意味:あなたは、コンテナの境界を取得するには、配列、またはstd::array、またはstd::vector、または特に大きな象—を使用するかどうか。これはあなたが必要とする、同じである

std::begin(vect), std::end(vect) 

コンテナ

4

begin()とend()を認識させることは可能ですか?

それはポインタのためstd::beginを実装することは可能だが、(あなたが言うように、サイズが不明であるため)std::endを実装することは不可能なので、少し無意味です。

ただし、std::findを使用するために、これらのいずれかを必要としない:

int* p = std::find(pStart, pStart + SIZE, 5); 
+1

これ以外は潜在的なバグがあります。このような手作業の境界は、ほとんど常に悪い考えです。 –

0

C++配列でイテレータを使用したいが、生ポインタも使用したい。

あなたはそれを後方に持っています。生ポインタは、イテレータです。それらは配列に対して反復処理を行います。

std::beginstd::endを使用すると、そうでなければ達成できるすべての機能に使用できます。特に、<algorithm>のC++標準アルゴリズムに渡すことができます。

ポインタ自体は反復できません。イテレータは反復できません。

int* pStart = vect; 
std::find(std::begin(pStart), std::end(pStart), 5); 

非常に緩く、ポインタがちょうど数である、話します。数字の「開始」と「終了」とは何ですか?

int i = 123; 
std::find(std::begin(i), std::end(i), 5); // error 

、それはそれのbegin()end()に認識させることは可能です:コードのこの作品は、次のようにほとんど意味がありませんか?

ポインタは、配列の先頭を指します。しかし、その知識はポインタと共に保持されなければならない。開始ポインタと共にサイズまたは終了ポインタを維持し、すべてのデータをまとめて保持する必要があります。

これはまさにstd::arraystd::vectorがあなたのために行うことです。

0

私は範囲のC++の一般的な治療法と互換性を持たせるための簡単なコンテナに依存している配列を扱います。例えば

#include <iostream> 
#include <memory> // for std::unique_ptr 
#include <algorithm> // for std::reverse 
#include <numeric> // for std::iota 

template<typename T> 

class range_view { 

public: 

    range_view(T* data, std::size_t size) 
     : m_data { data }, 
     m_size { size } { } 

    const T* begin() const { return m_data; } 
    const T* end() const { return m_data + m_size; } 

    T* begin() { return m_data; } 
    T* end() { return m_data + m_size; } 

private: 

    T* m_data; 
    std::size_t m_size; 
}; 

int main() { 

    // this is your actual data 
    auto pdata = std::make_unique<int>(20); 

    // this is a handle you use to work with your data 
    auto data_view = range_view<int>(pdata.get(), 20); 

    // for example, you can fill it with numbers 0, ... , N - 1 
    std::iota(data_view.begin(), data_view.end(), 0); 

    // it is now compatible with c++'s range-based operators 
    std::cout << "my data...\n"; 
    for(auto && item : data_view) std::cout << item << " "; 

    std::reverse(data_view.begin(), data_view.end()); 
    std::cout << "\nreversed...\n"; 
    for(auto && item : data_view) std::cout << item << " "; 
    std::cout << "\n"; 
} 

コンパイルと

$ g++ example.cpp -std=c++14 
$ ./a.out 
my data... 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
reversed... 
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 

を実行して、あなたはまだコンストラクタに正しい次元を渡すことを心配する必要があり、基礎となるポインタが削除された場合には、無残に失敗しますとにかくそれについて心配しなければなりませんでした。

関連する問題