যখন কোনও ভেক্টর বড় হয় তখন কীভাবে মুভ সিনটিক্স প্রয়োগ করতে হয়?


93

আমার std::vectorএকটি নির্দিষ্ট শ্রেণীর বস্তু রয়েছে A। ক্লাসটি অ-তুচ্ছ এবং এর কপিরাইট কনস্ট্রাক্টর এবং মুভ কনস্ট্রাক্টর সংজ্ঞায়িত রয়েছে।

std::vector<A>  myvec;

যদি আমি ভেক্টরকে Aবস্তুগুলি (যেমন ব্যবহার করে myvec.push_back(a)) পূরণ করি তবে ভেক্টর আকারে বৃদ্ধি পাবে, অনুলিপিটি অনুলিপি করার জন্য অনুলিপি নির্মাণকারীকে ব্যবহার করে A( const A&)ct

আমি কি কোনওভাবে প্রয়োগ করতে পারি যে Aপরিবর্তে শ্রেণীর মুভ কনস্ট্রাক্টর ব্যবহার করা হচ্ছে?


4
আপনি একটি সরানো সচেতন ভেক্টর বাস্তবায়ন ব্যবহার করে করতে পারেন।
কে-বেলো

4
কীভাবে আপনি এটি অর্জন করবেন দয়া করে কিছুটা সুনির্দিষ্ট হয়ে উঠতে পারেন?
বার্টউইম ভ্যান বেস্ট

4
আপনি কেবল একটি সরানো-সচেতন ভেক্টর বাস্তবায়ন ব্যবহার করুন। আপনার স্ট্যান্ডার্ড লাইব্রেরি বাস্তবায়ন (এটি কী বিটিডাব্লু?) সরানো-সচেতন নয় বলে মনে হচ্ছে। আপনি বুস্ট থেকে সরানো-সচেতন পাত্রে চেষ্টা করতে পারেন।
কে-বালো

4
ঠিক আছে, আমি জিসিসি ব্যবহার করি 4.5.1, যা সচেতন হয় is
বার্টউইম ভ্যান বেস্ট

আমার কোডে এটি অনুলিপি কনস্ট্রাক্টরকে বেসরকারী করতে কাজ করেছিল, যদিও মুভ কনস্ট্রাক্টরের স্পষ্টত "নোজিপ্ট" ছিল না।
আরনে

উত্তর:


130

আপনি সি ++ অবহিত (বিশেষভাবে প্রয়োজন std::vector) যে আপনার পদক্ষেপ কন্সট্রাকটর এবং বিনাশকারী ব্যবহার করে, নিক্ষেপ না noexcept। তারপরে ভেক্টর বড় হওয়ার সাথে সাথে মুভ কনস্ট্রাক্টরকে ডাকা হবে।

এইভাবে সম্মতিযুক্ত একটি মুভি কনডাক্টরকে ঘোষণা এবং প্রয়োগ করতে হয় std::vector:

A(A && rhs) noexcept { 
  std::cout << "i am the move constr" <<std::endl;
  ... some code doing the move ...  
  m_value=std::move(rhs.m_value) ; // etc...
}

যদি কনস্ট্রাক্টর না হয় noexcept,std::vector এটা ব্যবহার করতে পারবেন না, যেহেতু তারপর, এটা মান দ্বারা দাবি ব্যতিক্রম গ্যারান্টী নিশ্চিত করতে পারবে না।

স্ট্যান্ডার্ডে কী বলা হয়েছে সে সম্পর্কে আরও তথ্যের জন্য, সি ++ সরান শব্দার্থবিজ্ঞান এবং ব্যতিক্রমগুলি পড়ুন

বো এর কাছে ক্রেডিট যিনি ইঙ্গিত দিয়েছিলেন যে এটি ব্যতিক্রমগুলি সহ করতে পারে। কেরেক এসবির পরামর্শ বিবেচনা করুন এবং emplace_backসম্ভব হলে ব্যবহার করুন । এটা তোলে করতে দ্রুত (কিন্তু প্রায়ই নয়), এটা পরিষ্কার এবং আরো কম্প্যাক্ট হতে পারে, কিন্তু এছাড়াও আছে কিছু ফাঁদ (বিশেষ করে অ স্পষ্ট কনস্ট্রাকটর সঙ্গে) হয়।

সম্পাদনা করুন , প্রায়শই ডিফল্ট আপনি যা চান তা হ'ল: সরানো যায় এমন সমস্ত কিছু সরিয়ে দিন, বাকীটি অনুলিপি করুন। স্পষ্টভাবে এর জন্য জিজ্ঞাসা করতে, লিখুন

A(A && rhs) = default;

এটি করে আপনি যখন সম্ভব সম্ভব নন: ডিফল্ট মুভ কনস্ট্রাক্টরকে নোসেপ্ট হিসাবে সংজ্ঞায়িত করা হয় কি?

নোট করুন যে ভিজ্যুয়াল স্টুডিও 2015 এর প্রাথমিক সংস্করণগুলি এর পুরানো সংস্করণগুলিকে সমর্থন করলেও এটি সমর্থন করে না।


সুদ আউট, কিভাবে করে impl "জানি" কিনা value_type'র পদক্ষেপ ctor হয় noexcept? কলিং স্কোপটিও যদি কোনও noexceptফাংশন থাকে তখন সম্ভবত ভাষা ফাংশন কল প্রার্থীর সেটকে সীমাবদ্ধ করে ?
অরবিট

4
@ লাইটনেসেসেসিনআরবিত আমি ধরে নিলাম এটি এনএনপ্রেফারেন্স / ডাব্লু / সিপি / টাইপস / আইস_মোভ_কন্ট্রোসিটেবলের মতো কিছু করছে । কেবলমাত্র একটি মুভ কনস্ট্রাক্টর থাকতে পারে তাই এটি ঘোষণার মাধ্যমে পরিষ্কারভাবে সংজ্ঞায়িত করা উচিত।
জোহান লন্ডবার্গ

@ লাইটনেসেসেসিন অরবিত, আমি তখন থেকেই শিখেছি যে কোনও noexceptমুভ কনস্ট্রাক্টর আছে কিনা তা সত্যই জানার কোনও (মানক / দরকারী) উপায় নেই । is_nothrow_move_constructibleযদি কোনও nothrowঅনুলিপি নির্মাণকারী থাকে তবে তা সত্য হবে । আমি ব্যয়বহুল nothrowঅনুলিপি নির্মাণকারীদের কোনও বাস্তব ক্ষেত্রে সম্পর্কে অবগত নই তাই এটি স্পষ্ট নয় যে এটি সত্যই গুরুত্বপূর্ণ।
জোহান লন্ডবার্গ

আমার জন্য কাজ করে না। আমার ডেস্ট্রাক্টর, মুভ কনস্ট্রাক্টর এবং মুভ অ্যাসিগমেন্ট ফাংশনগুলি সমস্তই noexceptশিরোলেখ এবং বাস্তবায়ন উভয়ই চিহ্নিত করে এবং যখন আমি পুশ_ব্যাক করি (স্ট্যান্ড:; সরানো) তখনও এটি অনুলিপি কনস্ট্রাক্টরকে কল করে। আমি এখানে আমার চুল ছিঁড়ে ফেলছি।
অ্যালাস্টারজি

4
@ জোহান আমি সমস্যাটি খুঁজে পেয়েছি। আমি std::move()ভুল push_back()কল ব্যবহার করছিলাম । এই সময়ের মধ্যে একটি যখন আপনি কোনও সমস্যার জন্য এতটা সন্ধান করছেন যে আপনি সামনের সামনে সুস্পষ্ট ত্রুটি দেখতে পাচ্ছেন না। এবং তারপরে এটি মধ্যাহ্নভোজন ছিল এবং আমি আমার মন্তব্য মুছতে ভুলে গিয়েছিলাম।
অ্যালাস্টারজি

17

মজার বিষয় হল, gcc 4.7.2 এর ভেক্টর কেবল মুভ কনস্ট্রাক্টর ব্যবহার করে তবেই মুভ কনস্ট্রাক্টর এবং ডেস্ট্রাক্টর উভয়ই থাকে noexcept। একটি সহজ উদাহরণ:

struct foo {
    foo() {}
    foo( const foo & ) noexcept { std::cout << "copy\n"; }
    foo( foo && ) noexcept { std::cout << "move\n"; }
    ~foo() noexcept {}
};

int main() {
    std::vector< foo > v;
    for ( int i = 0; i < 3; ++i ) v.emplace_back();
}

এটি প্রত্যাশিত ফলাফল:

move
move
move

যাইহোক, যখন আমি অপসারণ noexceptথেকে ~foo(), ফলে আলাদা:

copy
copy
copy

আমার ধারণা এটি এই প্রশ্নেরও উত্তর দেয় ।


এটা আমার মনে হচ্ছে যে অন্যান্য উত্তর শুধুমাত্র পদক্ষেপ কন্সট্রাকটর সম্পর্কে কথা বলতে, না সম্পর্কে বিনাশকারী noexcept হতে হচ্ছে।
নিকোলা বেনিস

ঠিক আছে, এটি হওয়া উচিত, তবে এটি হিসাবে দেখা যাচ্ছে, জিসিসি ৪.7.২ এ এটি ছিল না। সুতরাং এই সমস্যাটি আসলে, সিসিটির ক্ষেত্রে নির্দিষ্ট ছিল। যদিও এটি জিসিসি 4.8.0 এ স্থির করা উচিত। দেখুন সংশ্লিষ্ট Stackoverflow প্রশ্ন
নিকোলা বেনেস

-1

মনে হচ্ছে, একমাত্র উপায় (সি ++ 17 এবং প্রথম দিকে), std::vectorপুনঃনির্ধারণের ক্ষেত্রে ব্যবহারের সরানো শব্দার্থবিজ্ঞান প্রয়োগ করার জন্য অনুলিপি করা হচ্ছে অনুলিপি নির্মাণকারী :)। এইভাবে এটি আপনার মুভ কনস্ট্রাক্টরগুলি ব্যবহার করবে বা চেষ্টা করে মারা যাবে, সংকলনের সময় :)।

অনেকগুলি বিধি রয়েছে যেখানে std::vectorপুনঃনির্ধারণের ক্ষেত্রে মুভ কনস্ট্রাক্টর ব্যবহার করা উচিত নয়, তবে এটি কোথায় ব্যবহার করবে তা সম্পর্কে কিছুই নয়।

template<class T>
class move_only : public T{
public:
   move_only(){}
   move_only(const move_only&) = delete;
   move_only(move_only&&) noexcept {};
   ~move_only() noexcept {};

   using T::T;   
};

লাইভ দেখান

বা

template<class T>
struct move_only{
   T value;

   template<class Arg, class ...Args, typename = std::enable_if_t<
            !std::is_same_v<move_only<T>&&, Arg >
            && !std::is_same_v<const move_only<T>&, Arg >
    >>
   move_only(Arg&& arg, Args&&... args)
      :value(std::forward<Arg>(arg), std::forward<Args>(args)...)
   {}

   move_only(){}
   move_only(const move_only&) = delete;   
   move_only(move_only&& other) noexcept : value(std::move(other.value)) {};    
   ~move_only() noexcept {};   
};

লাইভ কোড

আপনার Tশ্রেণিতে অবশ্যই noexceptমুভি কনস্ট্রাক্টর / অ্যাসিগমেন্ট অপারেটর এবং noexceptডেস্ট্রাক্টর থাকতে হবে। অন্যথায় আপনি সংকলন ত্রুটি পাবেন।

std::vector<move_only<MyClass>> vec;

4
এটি অনুলিপি নির্মাণকারী মুছে ফেলার প্রয়োজন হয় না। যদি মুভ কনস্ট্রাক্টর অযোগ্য হয় তবে এটি ব্যবহৃত হবে।
বালকি

@ বালকি এটি ব্যবহৃত হতে পারে। স্ট্যান্ডার্ড এখন এটি প্রয়োজন হয় না। এখানে আলোচনা google.com/a/isocpp.org/forum/…
টাওয়ার120
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.