কোনও ভেক্টরের কোনও উপাদান মোছা () কাজ করে না


10

আমার একটি ভেক্টর আছে আমার এটিতে সর্বশেষ 3 টি উপাদান মুছতে হবে। এই যুক্তি বর্ণিত। প্রোগ্রামটি ক্র্যাশ হয়ে গেছে। ভুল কী হতে পারে?

vector<float>::iterator d = X.end();
    for (size_t i = 1; i < 3; i++) {
        if (i == 1) X.erase(d);
        else X.erase(d - i);
    }

এখানে হত্যাকারী dআসলেই নেই। এটি এক-অতীতের শেষ ক্যানারি মানটি কেবলমাত্র শেষের সন্ধানের জন্য ব্যবহারযোগ্য vector। আপনি এটি সরাতে পারবেন না। এরপরে, আপনি কোনও পুনরুক্তি মুছার সাথে সাথে তা চলে গেছে। আপনি এটি সহ নিরাপদে কোনও কিছুর জন্য পরে ব্যবহার করতে পারবেন না d - i
ব্যবহারকারী 4581301

উত্তর:


9

যদি ভেক্টরে কমপক্ষে 3 টি আইটেম থাকে তবে শেষ 3 টি আইটেম মুছতে সহজ - কেবল পপ_ব্যাক 3 বার ব্যবহার করুন :

#include <vector>
#include <iostream>

int main() 
{
    std::vector<float> v = { 1, 2, 3, 4, 5 };
    for (int i = 0; i < 3 && !v.empty(); ++i)
       v.pop_back();

    for ( const auto &item : v ) std::cout << item << ' ';
        std::cout << '\n';
}

আউটপুট:

1 2

11

এটা অনির্ধারিত আচরণ পাস end()1-পরামিতির পুনরুক্তিকারীর erase()জমিদার। তা না হলেও, 1 ম লুপের পুনরাবৃত্তির পরে অবৈধ erase()করে নির্দিষ্ট উপাদানগুলিতে "এবং তার পরে" থাকা dপুনরাবৃত্তিকে অবৈধ করে দেয়।

std::vectorএকটি 2-প্যারামিটার erase()ওভারলোড রয়েছে যা অপসারণের জন্য বিভিন্ন উপাদানকে স্বীকার করে। আপনার কোনও ম্যানুয়াল লুপের দরকার নেই:

if (X.size() >= 3)
    X.erase(X.end()-3, X.end());

সরাসরি নমুনা


3

প্রথমত, X.end()ভেক্টরের শেষ উপাদানটিতে কোনও পুনরুক্তিকারীকে ফেরত দেয় না, এটি পরিবর্তকের পরিবর্তে ভেক্টরের শেষ উপাদানটির একটি উপাদানকে পুনরুদ্ধার করে, যা এমন উপাদান যা ভেক্টর প্রকৃতপক্ষে নিজস্ব নয়, এই কারণেই যখন আপনি চেষ্টা করেন X.erase(d)প্রোগ্রাম ক্রাশ সহ এটি মুছুন।

পরিবর্তে, ভেক্টরটিতে কমপক্ষে 3 টি উপাদান রয়েছে তবে আপনি নিম্নলিখিতটি করতে পারেন:

X.erase( X.end() - 3, X.end() );

যা পরিবর্তে তৃতীয় শেষ উপাদানটিতে যায় এবং এটি না হওয়া পর্যন্ত প্রতিটি উপাদান মুছে দেয় X.end()

সম্পাদনা: কেবলমাত্র স্পষ্ট করার জন্য, X.end()এটি একটি লিগ্যাসিআরডমএ্যাকসেসিট্রেটার যা বৈধ -অপারেশন যা নির্দিষ্ট করে অন্য একটি লেগ্যাসিআরডমএ্যাকসেসিটরেটরে ফিরে আসে নির্দিষ্ট করে


2

সংজ্ঞা end()থেকে cppreference হল:

ভেক্টর ধারকটিতে অতীত-শেষের উপাদানটি উল্লেখ করে একটি পুনরাবৃত্তি প্রদান করে।

এবং সামান্য নীচে:

এটি কোনও উপাদানকে নির্দেশ করে না, এবং সুতরাং এটি অবজ্ঞা করা হবে না।

অন্য কথায়, ভেক্টরের কোনও উপাদান নেই যা শেষ () নির্দেশ করে। যে dereferencing দ্বারা অ উপাদান পদ্ধতি মুছে ফেলুন () পুরনো, আপনি সম্ভবত মেমরি যা ভেক্টর অন্তর্গত নয় পরিবর্তনের করছে। অতএব কুৎসিত জিনিসগুলি সেখান থেকে ঘটতে পারে।

অন্তর অন্তর অন্তর্ভুক্ত "নিম্ন" মান এবং অন্তর থেকে "উচ্চ" মান বাদ দিয়ে অন্তরগুলিকে [নিম্ন, উচ্চ) হিসাবে বর্ণনা করা সাধারণ সি ++ কনভেনশন ।


2

আপনি এটি ব্যবহার করতে পারেন reverse_iterator:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<float> X = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};

    // start the iterator at the last element
    vector<float>::reverse_iterator rit = X.rbegin();

    // repeat 3 times
    for(size_t i = 0; i < 3; i++)
    {
        rit++;
        X.erase(rit.base());
    }

    // display all elements in vector X
    for(float &e: X)
        cout << e << '\n';

    return 0;
}

উল্লেখ করার মতো কয়েকটি বিষয় রয়েছে:

  • reverse_iterator ritএর শেষ উপাদানটি থেকে শুরু হয় vector X। এই অবস্থান বলা হয় rbegin
  • eraseiteratorসাথে কাজ করার জন্য ক্লাসিকের প্রয়োজন । আমরা ritফোন করে তা পেয়েছি base। তবে সেই নতুন পুনরাবৃত্তির আগাম ritদিক থেকে পরবর্তী উপাদানটির দিকে নির্দেশ করবে।
  • এজন্য আমরা ritফোন করার আগে baseএবং আগে অগ্রসর হইerase

এছাড়াও আপনি যদি আরও জানতে চান তবে reverse_iteratorআমি এই উত্তরটি দেখার পরামর্শ দিই ।


2

প্রশ্নের একটি মন্তব্য (এখন মুছে ফেলা হয়েছে) বলেছে যে "একজন পুনরাবৃত্তির জন্য অপারেটর নেই there's" যাইহোক, নিম্নলিখিত কোডগুলি উভয়ই সংস্থাপিত করে এবং কাজ করে MSVCএবং clang-clস্ট্যান্ডার্ড সেটটিকে হয় C++17বা C++14:

#include <iostream>
#include <vector>

int main()
{
    std::vector<float> X{ 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f };
    for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
    std::vector<float>::iterator d = X.end();
    X.erase(d - 3, d);  // This strongly suggest that there IS a "-" operator for a vector iterator!
    for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
    return 0;
}

operator-নিম্নলিখিতগুলির জন্য প্রদত্ত সংজ্ঞাটি নিম্নরূপ ( <vector>শিরোনামে):

    _NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
        _Vector_iterator _Tmp = *this;
        return _Tmp -= _Off;
    }

তবে, আমি অবশ্যই কোনও সি ++ ভাষা-আইনজীবি নই, এবং সম্ভবত এটি মাইক্রোসফ্টের 'বিপজ্জনক' এক্সটেনশনগুলির মধ্যে একটি is এটি অন্যান্য প্ল্যাটফর্ম / সংকলকগুলিতে কাজ করে কিনা তা জানতে আমি খুব আগ্রহী হব।


2
আমি মনে করি এটি বৈধ, যেহেতু কোনও ভেক্টরের পুনরাবৃত্তিগুলি এলোমেলো অ্যাক্সেস এবং -এই ধরণের পুনরাবৃত্তির জন্য সংজ্ঞায়িত।
পলম্যাক কেনজি

@ পলম্যাক কেঞ্জি প্রকৃতপক্ষে - ঝনঝন স্ট্যাটিক বিশ্লেষক (যা মানদণ্ডগুলির সাথে বেশ কঠোর হতে পারে) এ সম্পর্কে কোনও সতর্কতা দেয়নি।
অ্যাড্রিয়ান মোল

1
এমনকি যদি operator-পুনরাবৃত্তিকারীদের জন্য কোনও সংজ্ঞায়িত না করা হয় তবে আপনি কেবল std::advance()বা std::prev()পরিবর্তে ব্যবহার করতে পারেন ।
রেমি লেবউ

1

এই বিবৃতি

    if (i == 1) X.erase(d);

অপরিবর্তিত আচরণ আছে।

এবং এই বিবৃতিটি শেষ উপাদানটির আগে কেবলমাত্র উপাদানটিকে সরিয়ে ফেলার চেষ্টা করে

    else X.erase(d - i);

কারণ আপনার কেবল দুটি পুনরাবৃত্তির সাথে লুপ রয়েছে

for (size_t i = 1; i < 3; i++) {

আপনার নীচের মতো কিছু দরকার।

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

int main() 
{
    std::vector<float> v = { 1, 2, 3, 4, 5 };

    auto n = std::min<decltype( v.size() )>( v.size(), 3 ); 
    if ( n ) v.erase( std::prev( std::end( v ), n ), std::end( v ) );

    for ( const auto &item : v ) std::cout << item << ' ';
    std::cout << '\n';

    return 0;
}

প্রোগ্রাম আউটপুট হয়

1 2 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.