de-vraag
  • Pytania
  • Tagi
  • Użytkownicy
Powiadomienia
Nagrody
Rejestracja
Po zarejestrowaniu się, będziesz otrzymywać powiadomienia o odpowiedziach i komentarzach do swoich pytań.
Zaloguj się
Brak tłumaczeń pasujących do Twojego wyszukiwania Jeśli masz już konto, zaloguj się, aby sprawdzić nowe powiadomienia.
Za dodane pytania, odpowiedzi i komentarze przewidziane są nagrody.
Więcej
Źródło
Edytuj
 Jabberwocky
Jabberwocky
Question

Używanie std::vector jako widoku na surową pamięć

I'm using a external library which at some point gives me a raw pointer to an array of integers and a size.

Teraz chciałbym użyć std::vector, aby uzyskać dostęp i modyfikować te wartości w miejscu, zamiast uzyskiwać do nich dostęp za pomocą surowych wskaźników.

Oto artefaktyczny przykład, który wyjaśnia, o co chodzi:

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 
}

Oczekiwane dane wyjściowe:

1
2
3
4
5

Powodem jest to, że muszę zastosować algorytmy z <algorithm> (sortowanie, zamiana elementów itp.) na tych danych.

Z drugiej strony zmiana rozmiaru tego wektora nigdy nie zostanie zmieniona, więc push_back, erase, insert nie są wymagane do pracy na tym wektorze.

Mógłbym skonstruować wektor na podstawie danych z biblioteki, użyć modyfikacji tego wektora i skopiować dane z powrotem do biblioteki, ale to byłyby dwie pełne kopie, których chciałbym uniknąć, ponieważ zestaw danych mógłby być naprawdę duży.

36 2020-02-10T13:30:40+00:00 10
Angela Cojocari 17541
Edytowane pytanie 19. września 2021 в 7:34
 NathanOliver
NathanOliver
Edytowane pytanie 10. lutego 2020 в 1:44
Programowanie
c++
stdvector
Popular videos
Threads in C++
Threads in C++
4 lata temu
Optimizing the usage of std::vector in C++
Optimizing the usage of std::vector in C++
4 lata temu
Dynamic Arrays in C++ (std::vector)
Dynamic Arrays in C++ (std::vector)
4 lata temu
Vector w C++ - jak z niego korzystać? Po co używać vector?
Vector w C++ - jak z niego korzystać? Po co używać vector?
2 lata temu
#14 prosta tablica dynamiczna (std::vector)
#14 prosta tablica dynamiczna (std::vector)
1 rok temu
Use push back and pop back to add or remove elements from vectors (C++ programming tutorial)
Use push back and pop back to add or remove elements from vectors (C++ programming tutorial)
6 lat temu
Introduction au std::vector !
Introduction au std::vector !
1 rok temu
[C++]Créer et remplir un vector de STD::Vector !
[C++]Créer et remplir un vector de STD::Vector !
5 lat temu
Vector In C++ STL | C++ Tutorials for Beginners #71
Vector In C++ STL | C++ Tutorials for Beginners #71
1 rok temu
Kurs C++ odc. 10: Wskaźniki. Dynamiczne alokowanie pamięci
Kurs C++ odc. 10: Wskaźniki. Dynamiczne alokowanie pamięci
8 lat temu
Vector Paro Pro Durr Dental - Instrukcja obsługi
Vector Paro Pro Durr Dental - Instrukcja obsługi
1 rok temu
C++14 - 018 - Introdução à std::vector: parte 1
C++14 - 018 - Introdução à std::vector: parte 1
5 lat temu
C++14 - 019 - Introdução à std::vector: parte 2
C++14 - 019 - Introdução à std::vector: parte 2
5 lat temu
CODING C++: STD VECTOR
CODING C++: STD VECTOR
2 lata temu
vector | Библиотека стандартных шаблонов (stl) | Уроки | C++ | #1
vector | Библиотека стандартных шаблонов (stl) | Уроки | C++ | #1
4 lata temu
【第11回】std::vectorを用いたプログラミング(配列の利用)
【第11回】std::vectorを用いたプログラミング(配列の利用)
1 rok temu
Vector | C++ STL (Standard Template Library) | std::vector
Vector | C++ STL (Standard Template Library) | std::vector
1 rok temu
« Poprzedni
Następny »
 NutCracker
NutCracker
10. lutego 2020 в 1:38
2020-02-10T13:38:50+00:00
Więcej
Źródło
Edytuj
#42392154

C++20's std::span

Jeśli potrafisz używać C++20, możesz użyć std::span, która jest parą wskaźnik - długość, dającą użytkownikowi widok na sąsiadujący ciąg elementów. Jest to pewnego rodzaju std::string_view, i podczas gdy oba std::span i std::string_view są widokami nie posiadającymi właściciela, std::string_view jest widokiem tylko do odczytu.

Z dokumentów:

Zakres szablonu klasy opisuje obiekt, który może odnosić się do sąsiadujący ciąg obiektów z pierwszym elementem ciągu na pozycji zero. Rozpiętość może mieć albo zakres statyczny, w którym przypadek, gdy liczba elementów w sekwencji jest znana i zakodowana w typ, lub zakres dynamiczny.

Tak więc zadziałałoby:

#zawierając <span>
#include <iostream>
#zawierając <algorytm>

Int main() {\i1}
    int data[] = { 5, 3, 2, 1, 4 };
    std::span<int> s{data, 5};

    std::sort(s.begin(), s.end());

    dla (auto const i : s) {
        std::cout << i << "\n";
    }

    wrócić 0;
}

Sprawdź to [na żywo][1]

Ponieważ std::span jest w zasadzie parą wskaźnik - długość, można również użyć w następujący sposób:

rozmiar_t rozmiar = 0;
int *data = get_data_from_library(size);
std::span<int> s{data, size};

Uwaga: Nie wszystkie kompilatory obsługują std::span. Sprawdź wsparcie dla kompilatorów tutaj. UPDATE

Jeśli nie jesteś w stanie użyć C++20, możesz użyć gsl::span, która jest w zasadzie podstawową wersją standardu C++ std::span.

C++11 rozwiązanie

Jeśli jesteś ograniczony do standardu C++11, możesz spróbować wdrożyć swoją własną, prostą klasę span:

szablon<nazwa typowa T>
rozpiętość klasowa {
   T* ptr_;
   std::size_t len_;

publiczny:
    span(T* ptr, std::size_t len) noexcept
        : ptr_{ptr}, len_{len}
    {}

    T& operator[](int i) noexcept {
        wrócić *ptr_[i];
    }

    T const& operator[](int i) const noexcept {
        wrócić *ptr_[i];
    }

    std::size_t size() const noexcept {
        wróć len_;
    }

    T* begin() noexcept {\i0}
        wróć ptr_;
    }

    T* end() noexcept {\i0}
        wróć ptr_ + len_;
    }
};

Sprawdź wersję C++11 na żywo

[1]: https://godbolt.org/#g:!((g:!((g:))! ((h:codeEditor,i:(fontScale:14,j:1,lang:c%2B%2B,selection:(endColumn:2,endLineNumber:16,positionColumn:1,positionLineNumber:1,selectionStartColumn:2,selectionStartLineNumber:16,startColumn:1,startLineNumber:1),source: '%23include+%3Cspan%3E%0A%23include+%3Ciostream%3E%0A%23include+%3Calgorithm%3E%0A%0Aint+main()+%7B%0A++++int+data%5B%5D+%3D+%7B+5,+3,+2,+1,+4+%7D%3B%0A++++std: :span%3Cint%3E+s%7Bdata,+5%7D%3B%0A%0A++++std::sort(s. begin(),+s.end())%3B%0A%0A++++for+(auto+i+:+s)+%7B%0A++++++++std::cout+%3C%3C+i+%3C%3C+%22%5Cn%22%3B%0A++++%7D%0A%0A++++return+0%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:49. 85494633014216,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((g:! ((h:compiler,i:(compiler:gsnapshot,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'0',intel:'0',libraryCode:'1',trim:'1'),fontScale:14,j:2,lang:c%2B%2B,libs:! (),opcje:'-std%3Dc%2B%2B2a',wybór:(koniecKolumna:1,koniecLiniaNumer:1,pozycjaKolumna:1,pozycjaLiniaNumer:1,wybórStartKolumna:1,wybórStartLiniaNumer: 1,startColumn:1,startLineNumer:1),źródło:1),l:'5',n:'0',o:'x86-64+gcc+(trunk)+(edytor+%231,+Kompilator+%232)+C%2B%2B',t:'0')),k:50. 145053669857845,l:'4',m:50,n:'0',o:'',s:0,t:'0'),(g:! ((h:output,i:(compiler:2,editor:1,fontScale:14,wrap:'1'),l:'5',n:'0',o:'%232+with+x86-64+gcc+(trunk)',t:'0')),nagłówek:(),l:'4',m:50,n:'0',o:',s:0,t:'0')),k:50. 145053669857845,l:'3',n:'0',o:'',t:'0')),l:'2',n:'0',o:'',t:'0')),version:4


47
0
Solution / Answer
 眠りネロク
眠りネロク
10. lutego 2020 в 1:39
2020-02-10T13:39:54+00:00
Więcej
Źródło
Edytuj
#42392155

Problem polega na tym, że std::vector musi zrobić kopię elementów z tablicy, z którą ją inicjalizujesz, ponieważ posiada własność obiektów, które zawiera.

Aby tego uniknąć, można użyć obiektu slice dla tablicy (tj. podobnego do tego, co std::string_view to std::string). Możesz napisać własną implementację szablonu klasy array_view, której instancje są konstruowane poprzez zabranie surowego wskaźnika do pierwszego elementu tablicy i długości tablicy:

#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 nie przechowuje tablicy; po prostu trzyma wskaźnik na początku tablicy i długość tej tablicy. Dlatego, obiekty array_view są tanie w konstruowaniu i kopiowaniu.

Ponieważ array_view dostarcza początek() i end() funkcji członkowskich, można na nim używać standardowych algorytmów bibliotecznych (np. std::sort, std::find, std::lower_bound, itd.):

#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';
}

Wyjście:

1 2 3 4 5

Użyj std::span (lub gsl::span) zamiast tego

Powyższa implementacja odsłania koncepcję kryjącą się za obiektami slice. Jednak od C++20 możesz bezpośrednio użyć std::span zamiast tego. W każdym razie, można użyć gsl::span od C++14.

35
0
 churill
churill
10. lutego 2020 в 1:36
2020-02-10T13:36:09+00:00
Więcej
Źródło
Edytuj
#42392150

Ponieważ algorithm-library pracuje z iteratorami, możesz zachować tablicę.

Dla wskaźników i znanej długości tablicy

Tutaj możesz użyć surowych wskaźników jako iteratorów. Obsługują one wszystkie operacje, które obsługuje iterator (inkrementacja, porównanie dla równości, wartość itd...):

#include <iostream>
#include <algorithm>

int *get_data_from_library(int &size) {
    static int dane[] = {5,3,2,1,4};

    size = 5;

    return data;
}

int main()
{
    int size;
    int *data = get_data_from_library(size);

    std::sort(dane, dane + rozmiar);

    for (int i = 0; i < size; i++)
    {
        std::cout << dane[i] << "∗quot;;
    }
}

data wskazuje na pierwszy element tablicy jak iterator zwrócony przez begin(), a data + size wskazuje na element po ostatnim elemencie tablicy jak iterator zwrócony przez end().

Dla tablic

Tutaj możesz użyć std::begin() i std::end().

#include <iostream>
#include <algorithm>

int main()
{
    int dane[] = {5,3,2,1,4}; // surowe dane z biblioteki

    std::sort(std::begin(dane), std::end(dane)); // sortuj surowe dane w miejscu

    for (int i = 0; i < 5; i++)
    {
        std::cout << data[i] << "\n" // wyświetl posortowane dane surowe
    }
}

Ale pamiętaj, że to działa tylko wtedy, gdy data nie rozkłada się na wskaźnik, ponieważ wtedy brakuje informacji o długości.

24
0
 PooSH
PooSH
10. lutego 2020 в 1:36
2020-02-10T13:36:19+00:00
Więcej
Źródło
Edytuj
#42392151

Możesz uzyskać iteratory na surowych tablicach i używać ich w algorytmach:

    int data[] = {5,3,2,1,4};
    std::sort(std::begin(dane), std::end(dane));
    for (auto i : dane) {
        std::cout << i << std::endl;
    }

Jeśli pracujesz z surowymi wskaźnikami (ptr + size), to możesz użyć następującej techniki:

    size_t size = 0;
    int * data = get_data_from_library(size);
    auto b = dane;
    auto e = b + size;
    std::sort(b, e);
    for (auto it = b; it != e; ++it) {
        cout << *it << endl;
    }

UPD: Powyższy przykład jest jednak źle zaprojektowany. Biblioteka zwraca nam surowy wskaźnik, a my nie wiemy gdzie jest zaalokowany bufor i kto ma go zwolnić.

Zazwyczaj osoba wywołująca funkcję dostarcza jej bufor do wypełnienia danymi. W takim przypadku możemy wstępnie zaalokować wektor i użyć jego bazowego bufora:

    std::vector<int> v;
    v.resize(256); // zaalokować bufor na 256 liczb całkowitych
    size_t size = get_data_from_library(v.data(), v.size());
    // zmniejszamy się do rzeczywistych danych. Zauważ, że żadna realokacja pamięci ani kopiowanie nie jest tutaj wykonywane.
    v.resize(size);
    std::sort(v.begin(), v.end());
    for (auto i : v) {
        cout << i << endl;
    }

Używając C++11 lub wyżej możemy nawet sprawić, że get_data_from_library() będzie zwracało wektor. Dzięki operacji move, nie będzie kopiowania pamięci.

10
0
 eerorika
eerorika
10. lutego 2020 в 2:43
2020-02-10T14:43:48+00:00
Więcej
Źródło
Edytuj
#42392158

Now I'd like to use std::vector to access and modify these values in place

Nie możesz. To nie po to jest std::vector. std::vector zarządza swoim własnym buforem, który zawsze jest nabywany od podzielnika. Nigdy nie przejmuje on własności innego bufora (z wyjątkiem innego wektora tego samego typu).

Z drugiej strony, nie musisz też tego robić, ponieważ ...

Powodem jest to, że muszę zastosować algorytmy z (sortowanie, zamiana elementów itp.) na tych danych.

Te algorytmy działają na iteratorach. Wskaźnik jest iteratorem do tablicy. Nie potrzebujesz wektora:

std::sort(data, data + size);

W przeciwieństwie do szablonów funkcji w <algorycielu>, niektóre narzędzia, takie jak zakres-for,std::begin/std::end i C++20 nie działają jednak tylko z parą iteratorów, podczas gdy działają z kontenerami, takimi jak wektory. Możliwe jest stworzenie klasy wrapper dla iteratora + rozmiar, który zachowuje się jak zakres i działa z tymi narzędziami. C++20 wprowadzi taką klasę wrapper do standardowej biblioteki: std::span.

Angela Cojocari 17541
Edytowana odpowiedź 19. września 2021 в 7:35
6
0
 NathanOliver
NathanOliver
10. lutego 2020 в 1:37
2020-02-10T13:37:24+00:00
Więcej
Źródło
Edytuj
#42392152

Nie możesz'tego zrobić z std::vector bez zrobienia kopii. std::vector jest właścicielem wskaźnika, który ma pod maską i alokuje przestrzeń poprzez alokator, który jest dostarczany.

Jeśli masz dostęp do kompilatora, który obsługuje C++20, możesz użyć std::span, który został zbudowany dokładnie w tym celu. Zawija wskaźnik i rozmiar do "kontenera", który ma interfejs kontenera C++.

Jeśli nie, możesz użyć gsl::span, na którym bazuje standardowa wersja.

Jeśli nie chcesz importować innej biblioteki, możesz sam to zaimplementować, w zależności od tego, jaką funkcjonalność chcesz mieć.

Angela Cojocari 17541
Edytowana odpowiedź 19. września 2021 в 7:35
6
0
 Sneftel
Sneftel
10. lutego 2020 в 1:37
2020-02-10T13:37:36+00:00
Więcej
Źródło
Edytuj
#42392153

W rzeczywistości mógłbyś prawie użyć do tego celu std::vector, nadużywając funkcji własnego alokacji, aby zwrócić wskaźnik do pamięci, którą chcesz wyświetlić. Nie byłoby to zagwarantowane przez standard do pracy (wyściełanie, wyrównanie, inicjalizacja zwracanych wartości; musiałbyś cierpieć przy przypisywaniu początkowego rozmiaru, a dla nieprymitywnych musiałbyś również hakować swoje konstruktory), ale w praktyce oczekiwałbym, że da to wystarczająco dużo zmian.

Nigdy tego nie rób. To jest brzydkie, zaskakujące, hacky, i niepotrzebne. Standardowe algorytmy biblioteki są gotowe do pracy z surowymi tablicami, jak i z wektorami. Zobacz inne odpowiedzi, żeby dowiedzieć się więcej na ten temat.

Angela Cojocari 17541
Edytowana odpowiedź 19. września 2021 в 7:35
3
0
 darune
darune
10. lutego 2020 в 2:16
2020-02-10T14:16:03+00:00
Więcej
Źródło
Edytuj
#42392157

Poza innymi dobrymi sugestiami dotyczącymi std::span coming in [tag:c++20] i gsl:span, włączając w to własną (lekką) klasę span do tego czasu jest już wystarczająco łatwa (zachęcamy do kopiowania):

template<class T>
struct span {
    T* first;
    size_t length;
    span(T* first_, size_t length_) : first(first_), length(length_) {};
    using value_type = std::remove_cv_t<T>;//primarily needed if used with templates
    bool empty() const { return length == 0; }
    auto begin() const { return first; }
    auto end() const { return first + length; }
};

static_assert(_MSVC_LANG <= 201703L, "remember to switch to std::span");

Na szczególną uwagę zasługuje również biblioteka zakresów pobudzenia [tag:boost-range], jeśli jesteś zainteresowany bardziej ogólną koncepcją zakresu: https://www.boost.org/doc/libs/1_60_0/libs/range/doc/html/range/reference/utilities/iterator_range.html.

Koncepcje zakresów pojawią się również w [tag:c++20].

Angela Cojocari 17541
Edytowana odpowiedź 19. września 2021 в 7:35
3
0
Robert Andrzejuk
Robert Andrzejuk
10. lutego 2020 в 2:07
2020-02-10T14:07:13+00:00
Więcej
Źródło
Edytuj
#42392156

Możesz użyć std::reference_wrapper dostępnego od C++11:

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>

int main()
{
    int src_table[] = {5, 4, 3, 2, 1, 0};

    std::vector< std::reference_wrapper< int > > dest_vector;

    std::copy(std::begin(src_table), std::end(src_table), std::back_inserter(dest_vector));
    // if you don't have the array defined just a pointer and size then:
    // std::copy(src_table_ptr, src_table_ptr + size, std::back_inserter(dest_vector));

    std::sort(std::begin(dest_vector), std::end(dest_vector));

    std::for_each(std::begin(src_table), std::end(src_table), [](int x) { std::cout << x << '\n'; });
    std::for_each(std::begin(dest_vector), std::end(dest_vector), [](int x) { std::cout << x << '\n'; });
}
Angela Cojocari 17541
Edytowana odpowiedź 19. września 2021 в 7:35
1
0
 Arghnews
Arghnews
11. lutego 2020 в 11:11
2020-02-11T11:11:22+00:00
Więcej
Źródło
Edytuj
#42392159

Jak zauważyli inni, std::vector musi być właścicielem podstawowej pamięci (brak bałaganu z niestandardowym podzielnikiem), więc nie może być używany.

Inni również zalecili rozpiętość c++20, jednak oczywiście wymaga to c++20.

Ja polecam span-lite span. Cytując to, to jest napis:

span lite - rozpiętość podobna do C++20 dla C++98, C++11 i późniejszych w bibliotece tylko z nagłówkami w jednym pliku

Zapewnia niewłasność i zmienny widok (tak jak w przypadku mutacji elementów i ich kolejności, ale nie wstawiania ich) i jak mówi cytat, nie ma żadnych zależności i działa na większości kompilatorów.

Twój przykład:

#include <algorithm>
#include <cstddef>
#include <iostream>

#include <nonstd/span.hpp>

static int data[] = {5, 1, 2, 4, 3};

// For example
int* get_data_from_library()
{
  return data;
}

int main ()
{
  const std::size_t size = 5;

  nonstd::span<int> v{get_data_from_library(), size};

  std::sort(v.begin(), v.end());

  for (auto i = 0UL; i < v.size(); ++i)
  {
    std::cout << v[i] << "\n";
  }
}

Druki

1
2
3
4
5

Ma to również dodatkową zaletę, jeśli pewnego dnia przełączysz się na c++20, powinieneś po prostu być w stanie zastąpić to nonstd::span przez std::span.

Angela Cojocari 17541
Edytowana odpowiedź 19. września 2021 в 7:35
1
0
Dodaj pytanie
Kategorie
Wszystkie
Technologia
Kultura / Rekreacja
Życie / Sztuka
Nauka
Profesjonalny
Biznes
Użytkownicy
Wszystkie
Nowy
Popularny
1
Jasur Fozilov
Zarejestrowany 9 godzin temu
2
Zuxriddin Muydinov
Zarejestrowany 1 dzień temu
3
Денис Анненский
Zarejestrowany 3 dni temu
4
365
Zarejestrowany 1 tydzień temu
5
True Image
Zarejestrowany 1 tydzień temu
DE
ES
FR
IT
JA
KO
NL
PL
PT
RU
ZH
© de-vraag 2022
Źródło
stackoverflow.com
na podstawie licencji cc by-sa 3.0 z przypisaniem