স্টাড :: ভেক্টরটি কাঁচা মেমরির জন্য ব্যবহার করে


71

আমি একটি বাহ্যিক গ্রন্থাগার ব্যবহার করছি যা এক পর্যায়ে আমাকে পূর্ণসংখ্যার অ্যারের এবং একটি আকারকে একটি কাঁচা পয়েন্টার দেয়।

এখন আমি 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কাজ যে ভেক্টর প্রয়োজন নেই।

আমি গ্রন্থাগার থেকে প্রাপ্ত তথ্যের উপর ভিত্তি করে একটি ভেক্টর তৈরি করতে পারি, সেই ভেক্টরটি সংশোধন করতে এবং ডেটাটি লাইব্রেরিতে অনুলিপি করে ব্যবহার করতে পারি, তবে এটি দুটি সম্পূর্ণ অনুলিপি হতে হবে যা ডেটা সেটটি সত্যই বড় হতে পারে বলে আমি এড়াতে চাই।


16
আপনি যা খুঁজছেন তা অনুমানমূলক std::vector_view, তাই না?
眠 り ネ ロ ク

3
@ 眠 り ネ ロ ク হ্যাঁ, সম্ভবত
জ্যাবারওয়কি

5
এটি কিভাবে std::vectorকাজ করে না ।
জেস্পার জুহল


34
স্ট্যান্ডার্ড আলগোরিদিম iterators উপর কাজ করে এবং পয়েন্টার হয় iterators। আপনাকে কিছু করতে বাধা দেওয়ার কিছু নেই sort(arrayPointer, arrayPointer + elementCount);
মাস্টার -

উত্তর:


60

সমস্যাটি হ'ল 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একটি অ্যারে সঞ্চয় করে না; এটি ঠিক অ্যারের শুরুতে এবং সেই অ্যারের দৈর্ঘ্যের দিকে একটি পয়েন্টার ধরে থাকে holds অতএব, 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সি ++ 14 থেকে ব্যবহার করতে পারেন ।


আপনি কেন এই পদ্ধতিগুলিকে অযোগ্য হিসাবে চিহ্নিত করেছেন? আপনি কোনও গ্যারান্টি দিতে পারবেন না যে কোনও ব্যতিক্রম ছোঁড়া হচ্ছে না, আপনি কি পারেন?
সোনেক্সো


@ মূউইইপি কেবল একটি লিঙ্কের চেয়ে কিছু ব্যাখ্যা রেখে দেওয়া ভাল। ভবিষ্যতে লিঙ্কটির মেয়াদ শেষ হতে পারে যখন আমি এটি অনেক ঘটতে দেখেছি।
জেসন লিউ

63

সি ++ 20 এর std::span

আপনি যদি সি ++ ২০ ব্যবহার করতে সক্ষম হন তবে আপনি এটি ব্যবহার করতে পারেন std::spanযা কোন পয়েন্টার - দৈর্ঘ্যের জুড়ি যা ব্যবহারকারীকে উপাদানগুলির একটি ধারাবাহিক অনুক্রমের জন্য একটি দৃষ্টিভঙ্গি দেয়। এটি কোনও এক ধরণের std::string_view, এবং উভয়ই std::spanএবং std::string_viewঅ-মালিকানাধীন মতামত, std::string_viewকেবল পঠনযোগ্য দর্শন।

ডক্স থেকে:

শ্রেণীর টেমপ্লেট স্প্যান এমন একটি বস্তুর বর্ণনা দেয় যা শূন্যের অবস্থানের ক্রমের প্রথম উপাদান সহ অবজেক্টগুলির একটি সুসংগত অনুক্রমকে নির্দেশ করতে পারে। একটি স্প্যানের হয় একটি স্থিতিশীল পরিমাণ থাকতে পারে, সেক্ষেত্রে অনুক্রমের উপাদানগুলির সংখ্যাটি টাইপটিতে পরিচিত এবং এনকোডড হয়, বা একটি গতিশীল পরিমাণে।

সুতরাং নিম্নলিখিত কাজ করবে:

#include <span>
#include <iostream>
#include <algorithm>

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

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

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

    return 0;
}

এটি সরাসরি দেখুন

যেহেতু std::spanমূলত পয়েন্টার - দৈর্ঘ্যের জুটি, তাই আপনি নিম্নলিখিত পদ্ধতিতেও ব্যবহার করতে পারেন:

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

দ্রষ্টব্য: সমস্ত সংকলক সমর্থন করে না std::span। সংকলক সমর্থন এখানে চেক করুন

হালনাগাদ

আপনি যদি সি ++ ২০ ব্যবহার করতে না সক্ষম হন তবে আপনি ব্যবহার করতে পারেন gsl::spanযা মূলত সি ++ স্ট্যান্ডার্ডের মূল সংস্করণ std::span

সি ++ 11 সমাধান

আপনি যদি সি ++ 11 স্ট্যান্ডার্ডের মধ্যে সীমাবদ্ধ থাকেন তবে আপনি নিজের সাধারণ spanক্লাস প্রয়োগের চেষ্টা করতে পারেন :

template<typename T>
class span {
   T* ptr_;
   std::size_t len_;

public:
    span(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];
    }

    std::size_t size() const noexcept {
        return len_;
    }

    T* begin() noexcept {
        return ptr_;
    }

    T* end() noexcept {
        return ptr_ + len_;
    }
};

সি ++ 11 সংস্করণটি সরাসরি দেখুন


4
gsl::spanআপনার std::span
সংকলকটি

2
@ আর্টিয়ার আমি এই সাথে আমার উত্তর আপডেট করব। ধন্যবাদ
নটক্র্যাকার

29

যেহেতু অ্যালগরিদম-গ্রন্থাগার পুনরাবৃত্তকারীদের সাথে কাজ করে আপনি অ্যারে রাখতে পারেন।

পয়েন্টার এবং জ্ঞাত অ্যারে দৈর্ঘ্যের জন্য

এখানে আপনি পুনরাবৃত্তকারী হিসাবে কাঁচা পয়েন্টার ব্যবহার করতে পারেন। তারা কোনও অপারেটর সমর্থন করে এমন সমস্ত অপেরেশন সমর্থন করে (বর্ধন, সাম্যের জন্য তুলনা, এর মান ইত্যাদি ...):

#include <iostream>
#include <algorithm>

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

    size = 5;

    return data;
}


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

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

    for (int i = 0; i < size; i++)
    {
        std::cout << data[i] << "\n";
    }
}

dataডায়ার্ট অ্যারে সদস্যকে পয়েন্ট করে যেমন কোনও ইটারেটর ফিরে আসে begin()এবং data + sizeঅ্যারের শেষ এলিমেন্টের পরে এলিটরেটারের মতো ফিরে আসে বলে এলিমেন্টটিকে নির্দেশ করে end()

অ্যারে জন্য

এখানে আপনি ব্যবহার করতে পারেন std::begin()এবংstd::end()

#include <iostream>
#include <algorithm>

int main()
{
    int data[] = {5,3,2,1,4};         // raw data from library

    std::sort(std::begin(data), std::end(data));    // sort raw data in place

    for (int i = 0; i < 5; i++)
    {
        std::cout << data[i] << "\n";   // display sorted raw data 
    }
}

তবে মনে রাখবেন যে এটি কেবলমাত্র কাজ করে, যদি dataকোনও পয়েন্টারটির ক্ষয় না হয়, কারণ দৈর্ঘ্যের তথ্য হারিয়ে যায়।


7
এটি সঠিক উত্তর। অ্যালগোরিদম ব্যাপ্তির জন্য প্রযোজ্য । ধারকগুলি (যেমন, স্টাড :: ভেক্টর) ব্যাপ্তি পরিচালনা করার এক উপায়, তবে এগুলি একমাত্র উপায় নয়।
পিট বেকার

13

আপনি কাঁচা অ্যারেতে পুনরাবৃত্তি পেতে পারেন এবং এটিকে অ্যালগরিদমে ব্যবহার করতে পারেন:

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

আপনি যদি কাঁচা পয়েন্টার (পিটিআর + আকার) দিয়ে কাজ করছেন তবে আপনি নিম্নলিখিত কৌশলটি ব্যবহার করতে পারেন:

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

ইউপিডি: তবে উপরের উদাহরণটি খারাপ ডিজাইনের। লাইব্রেরিটি আমাদের একটি কাঁচা পয়েন্টার দেয় এবং আমরা জানি না কোথায় অন্তর্নিহিত বাফার বরাদ্দ করা হয়েছে এবং কে এটি মুক্ত করবে বলে মনে করা হচ্ছে।

সাধারণত, কলার ডেটা পূরণ করার জন্য ফাংশনটির জন্য একটি বাফার সরবরাহ করে। সেক্ষেত্রে, আমরা ভেক্টরকে প্রিলোকল্ট করতে পারি এবং এর অন্তর্নিহিত বাফারটি ব্যবহার করতে পারি:

    std::vector<int> v;
    v.resize(256); // allocate a buffer for 256 integers
    size_t size = get_data_from_library(v.data(), v.size());
    // shrink down to actual data. Note that no memory realocations or copy is done here.
    v.resize(size);
    std::sort(v.begin(), v.end());
    for (auto i : v) {
        cout << i << endl;
    }

সি ++ 11 বা তার বেশি ব্যবহার করার সময় আমরা ভেক্টরকে ফেরত পেতে get_data_from_library ()ও করতে পারি। অপারেশন সরানোর জন্য ধন্যবাদ, কোন মেমরি অনুলিপি থাকবে না।


2
তারপরে আপনি নিয়মিত পয়েন্টারগুলি auto begin = data; auto end = data + size;
পুনরাবৃত্তকারী

যাইহোক, প্রশ্নটি এসেছে যে ফিরে আসা ডেটা get_data_from_library()বরাদ্দ করা হয়? সম্ভবত আমাদের এটি একেবারে পরিবর্তন করার কথা নয়। আমাদের যদি লাইব্রেরিতে কোনও বাফার পাস করার দরকার হয় তবে আমরা ভেক্টর বরাদ্দ করতে পারি এবং পাস করতে পারিv.data()
PooSH

1
@ পুশ ডেটাটি লাইব্রেরির মালিকানাধীন, তবে কোনও বাধা ছাড়াই এটি পরিবর্তন করা যেতে পারে (এটি আসলে পুরো প্রশ্নের মূল বিষয়)। কেবলমাত্র ডেটার আকার পরিবর্তন করা যায় না।
জ্যাবারওয়াকি

1
@ জ্যাবারওয়ার্কি কীভাবে ডেটা পূরণ করতে ভেক্টরের অন্তর্নিহিত বাফারটি ব্যবহার করবেন তার একটি আরও ভাল উদাহরণ যোগ করেছেন
PooSH

9

আপনি std::vectorঅনুলিপি তৈরি না করে এটি দিয়ে পারবেন না । std::vectorএটি হুডের নীচে থাকা পয়েন্টারের মালিক এবং সরবরাহকৃত বরাদ্দের মাধ্যমে স্থান বরাদ্দ করে।

আপনার যদি এমন একটি সংকলকের অ্যাক্সেস থাকে যা সি ++ ২০ এর জন্য সমর্থন করে তবে আপনি স্ট্যান্ড :: স্প্যান ব্যবহার করতে পারেন যা ঠিক এই উদ্দেশ্যে নির্মিত হয়েছিল। এটি একটি পয়েন্টার এবং আকারকে একটি "ধারক" এ আবৃত করে যাতে সি ++ ধারক ইন্টারফেস রয়েছে।

যদি তা না হয় তবে আপনি জিএসএল :: স্প্যান ব্যবহার করতে পারেন যা স্ট্যান্ডার্ড সংস্করণটি বন্ধ করে দেওয়া হয়েছিল।

আপনি যদি অন্য কোনও লাইব্রেরি আমদানি করতে না চান তবে আপনার নিজের যাবতীয় কার্যকারিতা থাকতে চান তার উপর নির্ভর করে আপনি নিজেকে নিতান্তই বাস্তবায়িত করতে পারেন।


9

এখন আমি এই মানগুলিকে স্থানে অ্যাক্সেস এবং সংশোধন করতে std :: ভেক্টর ব্যবহার করতে চাই

তুমি পার না. এটা কি std::vectorজন্য নয়। std::vectorনিজস্ব বাফার পরিচালনা করে, যা সর্বদা একটি বরাদ্দকারী থেকে নেওয়া হয়। এটি কখনই অন্য বাফারের মালিকানা গ্রহণ করে না (একই ধরণের অন্য ভেক্টর ব্যতীত)।

অন্যদিকে, আপনারও দরকার নেই কারণ ...

কারণটি হ'ল আমাকে সেই ডেটাতে (বাছাইকরণ, সোয়াপিং উপাদানগুলি ইত্যাদি) থেকে অ্যালগরিদম প্রয়োগ করতে হবে।

এই আলগোরিদিমগুলি পুনরাবৃত্তকারীগুলিতে কাজ করে। একটি পয়েন্টার একটি অ্যারেতে পুনরাবৃত্তি হয়। আপনার কোনও ভেক্টর লাগবে না:

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

এতে ফাংশন টেম্পলেটগুলির বিপরীতে <algorithm>, কিছু সরঞ্জাম যেমন রেঞ্জ-ফর, std::begin/ std::endএবং সি ++ 20 রেঞ্জগুলি কেবল পুনরায় পুনরুক্তিকারীদের সাথে কাজ করে না, যদিও তারা ভেক্টরগুলির মতো ধারকগুলি নিয়ে কাজ করে। পুনরুক্তি হিসাবে আকারে আচরণ করে এবং এই সরঞ্জামগুলির সাথে কাজ করে এমন পুনরাবৃত্তকারী + আকারের জন্য একটি মোড়কের ক্লাস তৈরি করা সম্ভব। সি ++ 20 মান গ্রন্থাগার মধ্যে যেমন মোড়কের পরিচয় করিয়ে দিতে হবে: std::span


7

সম্পর্কে অন্যান্য ভাল পরামর্শ এছাড়া std::spanআসছে এবং gsl:spanআপনার নিজস্ব (লাইটওয়েট) সহ, spanবর্গ পর্যন্ত তারপর সহজ যথেষ্ট ইতিমধ্যে (কপি বিনা দ্বিধায়) হল:

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");

বিশেষ নোটটি হ'ল আপনি আরও জেনেরিক পরিসর ধারণার বিষয়ে আগ্রহী হন তবে ব্রেস্ট রেঞ্জের লাইব্রেরি হ'ল : https://www.boost.org/doc/libs/1_60_0/libs/range/doc/html/range/references / ইউটিলিটিস / সাইটেটর_রেঞ্জ.ইচটিএমএল

সীমার ধারণাগুলিও আসবে


1
কিসের using value_type = std::remove_cv_t<T>;জন্য?
জ্যাবারওয়কি

1
... এবং আপনি কন্সট্রাকটর ভুলে গেছি: span(T* first_, size_t length) : first(first), length(length) {};। আমি আপনার উত্তর সম্পাদনা করেছি।
জ্যাবারওয়াকি

@ জ্যাবারওয়ার্কি আমি সবেমাত্র সামগ্রিক সূচনা ব্যবহার করেছি। তবে কনস্ট্রাক্টর ঠিক আছে।
darune

1
@ সম্রাটিকা আমি অনুমান করি আপনি ঠিক বলেছেন, আমি নন-
কনস্ট্যান্ট

1
using value_type = std::remove_cv_t<T>;প্রধানত যদি (একটি 'সীমার' এর VALUE_TYPE পাবার জন্য) টেমপ্লেট প্রোগ্রামিং সঙ্গে ব্যবহার প্রয়োজন হয়। আপনি যদি কেবল পুনরুক্তি ব্যবহার করতে চান তবে আপনি এড়িয়ে / মুছতে পারেন।
darune

6

আপনি দেখতে চান মেমরিটিতে একটি পয়েন্টার ফিরিয়ে আনতে কাস্টম বরাদ্দকারী কার্যকারিতাটি আপত্তিজনকভাবে ব্যবহার করে আপনি এটি প্রায় ব্যবহার std::vectorকরতে পারেন। এটি স্ট্যান্ডার্ডের সাথে কাজ করার নিশ্চয়তা দেয় না (প্যাডিং, প্রান্তিককরণ, প্রত্যাবর্তিত মানগুলির সূচনা); প্রাথমিক আকার নির্ধারণের সময় আপনাকে ব্যথা নিতে হবে এবং অ-আদিমদের জন্য আপনাকেও আপনার নির্মাণকারীদের হ্যাক করতে হবে ), তবে বাস্তবে আমি এটির পক্ষে যথেষ্ট টুইটগুলি প্রত্যাশা করব।

কখনও কখনও যে না। এটি কুৎসিত, অবাক, হ্যাক এবং অপ্রয়োজনীয়। স্ট্যান্ডার্ড লাইব্রেরির অ্যালগরিদমগুলি ইতিমধ্যে ভেক্টরগুলির মতো কাঁচা অ্যারেগুলির সাথে কাজ করার জন্য ডিজাইন করা হয়েছে। বিস্তারিত জানার জন্য অন্যান্য উত্তরগুলি দেখুন।


1
হুঁ, হ্যাঁ যা vectorনির্মাণকারীদের সাথে কাজ করতে পারে যা একটি কাস্টম অলোকেটর রেফারেন্সকে কনস্ট্রাক্টর আর্গ হিসাবে (কেবলমাত্র কোনও টেম্পলেট প্যারাম নয়) হিসাবে গ্রহণ করে। আমার ধারণা আপনার একটি বরাদ্দকারী অবজেক্টের দরকার আছে যাটিতে রানটাইম পয়েন্টার মান রয়েছে, এটি কোনও টেম্পলেট প্যারামিটার হিসাবে নয় অন্যথায় এটি কেবল কনস্টেক্সপ্র ঠিকানাগুলির জন্যই কাজ করতে পারে। আপনাকে অবশ্যই vectorডিফল্ট-নির্মাণের অবজেক্টগুলি .resize()বিদ্যমান ডেটা ওভাররাইট করতে না দেওয়ার বিষয়ে সতর্ক থাকতে হবে ; মতো মালিক ধারক এত অমিল ভেক্টর বনাম অ মালিক বিঘত বিশাল যদি আপনি ব্যবহার শুরু .push_back ইত্যাদি
পিটার Cordes

1
@PeterCordes আমি বলতে চাচ্ছি, এর Lede না সমাহিত করা যাক - আপনি চাই এছাড়াও পাগল হতে হবে। আমার মতে, ধারণাটির মধ্যে সবচেয়ে constructআশ্চর্যের বিষয় হ'ল বরাদ্দকারী ইন্টারফেসে এমন পদ্ধতি রয়েছে যা প্রয়োজন হবে ... আমি ভাবতে পারি না হ্যাকি-ব্যবহারের ক্ষেত্রে কিসের প্রয়োজন হবে না place
স্নেফটেল

1
সুস্পষ্ট ব্যবহারের ক্ষেত্রটি হ'ল আপনি অন্য কোনও উপায়ে লিখতে চলেছেন এমন উপাদানগুলি তৈরির সময় নষ্ট করা এড়াতে resize()যেমন, কোনও বিশুদ্ধ আউটপুট (যেমন একটি রিড সিস্টেম কল) হিসাবে এটি ব্যবহার করতে চায় এমন কোনও রেফারেন্স দেওয়ার আগে in অনুশীলন সংকলকগুলিতে প্রায়শই সেই স্মৃতি বা যা কিছু অপরিহার্য হয় না। অথবা যদি আপনার কাছে এমন একটি বরাদ্দকারী থাকে যা প্রাক-জিরো মেমরি পাওয়ার জন্য কলোক ব্যবহার করে, আপনি std::vector<int>যখন শূন্য বিট প্যাটার্নযুক্ত ডিফল্ট-নির্মাণকারী অবজেক্টগুলিতে ডিফল্টরূপে বোকামির মতো করেন তখন এটিকে নষ্ট করাও এড়াতে পারেন। En.cppreferences.com/w/cpp/container/vector/vector- এ
পিটার

4

অন্যরা যেমন উল্লেখ করেছে, std::vectorঅবশ্যই অন্তর্নিহিত মেমরির মালিকানাধীন (কাস্টম বরাদ্দকারীর সাথে জগাখিচির সংক্ষিপ্ততা) যাতে ব্যবহার করা যায় না।

অন্যরাও সি ++ ২০ এর স্প্যানের প্রস্তাব দিয়েছেন, তবে স্পষ্টতই এর জন্য সি ++ ২০ প্রয়োজন।

আমি স্প্যান-লাইট স্প্যানটি সুপারিশ করব । এটি উপশিরোনাম উদ্ধৃত:

স্প্যান লাইট - সি ++ 98 এর জন্য সি ++ 20 -র মতো স্প্যান এবং পরে কেবলমাত্র একক-ফাইলের শিরোনাম-পাঠাগারটিতে

এটি একটি মালিকানাবিহীন এবং পরিবর্তনীয় দৃশ্য সরবরাহ করে (যেমন আপনি উপাদানগুলিকে এবং তাদের ক্রমকে রূপান্তর করতে পারেন তবে সেগুলি সন্নিবেশ করতে পারেন না) এবং উদ্ধৃতিতে যেমন কোনও নির্ভরতা নেই এবং বেশিরভাগ সংকলকগুলিতে কাজ করে।

আপনার উদাহরণ:

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

ছাপে

1
2
3
4
5

এটিতে অতিরিক্ত সংযোজন রয়েছে যদি একদিন আপনি সি ++ ২০ এ স্যুইচ করেন তবে আপনাকে কেবল এটির nonstd::spanসাথে প্রতিস্থাপন করতে সক্ষম হওয়া উচিত std::span


3

আপনি std::reference_wrapperসি ++ 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'; });
}

2
এটি ডেটার একটি অনুলিপি সম্পাদন করে এবং আমি অবশ্যই এড়াতে চাই।
জ্যাবারওয়াকি

1
@ জ্যাবারওয়ার্কি এই তথ্যটি অনুলিপি করে না। তবে আপনি প্রশ্নটিতে যা চেয়েছিলেন তা নয়।
এরেরিকা

@ এরেরিকা std::copy(std::begin(src_table), std::end(src_table), std::back_inserter(dest_vector));অবশ্যই dest_vectorগ্রহণ করা মানগুলি অবশ্যই পূরণ করে src_table( আইওডিতে ডেটা অনুলিপি করা হয় dest_vector), সুতরাং আমি আপনার মন্তব্য পাইনি। আপনি ব্যাখ্যা করতে পারেন?
জ্যাবারওয়াকি

@ জ্যাবারওয়ার্কি এটির মূল্যগুলি অনুলিপি করে না। এটি ভেক্টরকে রেফারেন্স মোড়কের সাথে পূরণ করে।
এরেরিকা

3
@ জ্যাবারওয়ার্কি পূর্ণসংখ্যার মানগুলির ক্ষেত্রে এটি আরও অদক্ষ।
এরেরিকা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.