[解決済み] std::vectorを生メモリへのビューとして使用する。
質問
外部ライブラリを使っているのですが、ある時点で整数の配列への生ポインタとサイズが渡されます。
ここで、私は
std::vector
を使って、生のポインタでアクセスするのではなく、その場でこれらの値にアクセスし、変更したいと思います。
この点を説明する明確な例です。
size_t size = 0;
int * data = get_data_from_library(size); // raw data from library {5,3,2,1,4}, size gets filled in
std::vector<int> v = ????; // pseudo vector to be used to access the raw data
std::sort(v.begin(), v.end()); // sort raw data in place
for (int i = 0; i < 5; i++)
{
std::cout << data[i] << "\n"; // display sorted raw data
}
期待される出力
1
2
3
4
5
のアルゴリズムを適用する必要があるからです。
<algorithm>
(ソート、要素の入れ替えなど) のアルゴリズムをそのデータに適用する必要があるからです。
一方、そのベクトルのサイズを変更すると、決して変更されないので
push_back
,
erase
,
insert
はそのベクターで動作する必要はありません。
ライブラリからのデータに基づいてベクトルを構築し、そのベクトルを修正してライブラリにデータをコピーして使用することもできますが、データセットが非常に大きくなる可能性があるため、完全なコピーを2つ作成することになり、それは避けたいと思います。
どのように解決するのですか?
問題点は
std::vector
は、それが含むオブジェクトの所有権を持っているため、初期化した配列から要素のコピーを作成しなければならないことです。
これを回避するために
スライス
オブジェクトを配列に使用することができます。
std::string_view
が
std::string
). 自分で書くことができる
array_view
クラスのテンプレート実装を書くことができます。そのインスタンスは、配列の最初の要素への生のポインタと配列の長さを取ることによって構築されます。
#include <cstdint>
template<typename T>
class array_view {
T* ptr_;
std::size_t len_;
public:
array_view(T* ptr, std::size_t len) noexcept: ptr_{ptr}, len_{len} {}
T& operator[](int i) noexcept { return ptr_[i]; }
T const& operator[](int i) const noexcept { return ptr_[i]; }
auto size() const noexcept { return len_; }
auto begin() noexcept { return ptr_; }
auto end() noexcept { return ptr_ + len_; }
};
array_view
は配列を格納するのではなく、配列の先頭へのポインタとその配列の長さを保持するだけです。したがって
array_view
オブジェクトは構築するのもコピーするのも簡単です。
から
array_view
は
begin()
と
end()
のメンバ関数を使用する場合は、標準ライブラリのアルゴリズム(例えば
std::sort
,
std::find
,
std::lower_bound
など)がついています。
#define LEN 5
auto main() -> int {
int arr[LEN] = {4, 5, 1, 2, 3};
array_view<int> av(arr, LEN);
std::sort(av.begin(), av.end());
for (auto const& val: av)
std::cout << val << ' ';
std::cout << '\n';
}
出力します。
1 2 3 4 5
使用方法
std::span
(または
gsl::span
) の代わりに
上記の実装は
スライスオブジェクト
. しかし、C++20 以降では、直接
std::span
を代わりに使うことができます。 いずれにせよ
gsl::span
を C++14 以降で使用することができます。
関連
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み】変数やフィールドがvoid宣言されている
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] C++11の'typedef'と'using'の違いは何ですか?
-
[解決済み] std::vector にある項目が存在するかどうかを調べるには?
-
[解決済み] std::vectorをハードコードされた要素で初期化する最も簡単な方法は何ですか?
-
[解決済み] const std::string & をパラメータとして渡す時代は終わったのでしょうか?
-
[解決済み] std::vector<> からインデックスで要素を消すにはどうしたらいいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テスト
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】浮動小数点例外エラーが発生する: 8
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み】C++ - ステートメントがオーバーロードされた関数のアドレスを解決できない。
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み】変数やフィールドがvoid宣言されている
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された