এসটিডি :: ভেক্টর কি পুশ_ব্যাক দিয়ে অবজেক্ট অনুলিপি করছে?


168

ভালগ্রাইন্ডের সাথে প্রচুর তদন্তের পরে, আমি এই সিদ্ধান্তে পৌঁছেছি যে std :: ভেক্টর আপনাকে ধাক্কা দিতে চাইবে এমন একটি বস্তুর অনুলিপি তৈরি করে।

এটা কি সত্যি? কোনও ভেক্টর কোনও অনুলিপি ছাড়াই কোনও জিনিসের রেফারেন্স বা পয়েন্টার রাখতে পারবেন না ?!

ধন্যবাদ


20
এটি সি ++ এর একটি প্রাথমিক নীতি। অবজেক্টস মান। অ্যাসাইনমেন্ট একটি অনুলিপি তৈরি করে। একই অবজেক্টের সাথে উল্লেখ করে দুটি ভেরিয়েবল সম্ভব নয় যতক্ষণ না আপনি পয়েন্টার বা রেফারেন্সটি দিয়ে টাইপটি সংশোধন করেন *বা &না করেন।
ড্যানিয়েল আরউইকার

8
@ ড্যানিয়েলআরওয়িকার পুশ_ব্যাক আসলে একটি রেফারেন্স নেয়। এটি স্বাক্ষর থেকে একথা পরিষ্কার নয় যে এটি একটি অনুলিপি তৈরি করবে।
ব্রায়ান গর্ডন

3
@ ব্রায়ান গর্ডন - এটি হচ্ছে না! অতএব গাইডিং নীতিটির প্রয়োজন। তবুও, আমরা এর স্বাক্ষর থেকে কিছুটা কাটাতে পারি push_back: এটি লাগে a const&। হয় এটি মানটিকে দূরে ফেলে (অকেজো), অথবা একটি পুনরুদ্ধার পদ্ধতি রয়েছে। সুতরাং আমরা স্বাক্ষরটি দেখি back, এবং এটি সরল প্রত্যাবর্তন করে &, তাই হয় মূল মানটি অনুলিপি করা হয়েছিল বা constনীরবে চুপচাপ ফেলে দেওয়া হয়েছে (খুব খারাপ: সম্ভাব্য অপরিবর্তিত আচরণ)। সুতরাং ধরে নিই যে এর ডিজাইনারগুলি vectorযুক্তিযুক্ত ছিল ( vector<bool>প্রতিরোধ না করে) আমরা এই সিদ্ধান্তে পৌঁছেছি যে এটি অনুলিপিগুলি তৈরি করে।
ড্যানিয়েল আরউইকার

উত্তর:


183

হ্যাঁ, std::vector<T>::push_back()যুক্তির একটি অনুলিপি তৈরি করে এবং এটি ভেক্টরে সংরক্ষণ করে stores আপনি যদি আপনার ভেক্টরের অবজেক্টে পয়েন্টার সঞ্চয় করতে চান তবে এর std::vector<whatever*>পরিবর্তে একটি তৈরি করুন std::vector<whatever>

যাইহোক, আপনাকে অবশ্যই এটি নিশ্চিত করতে হবে যে পয়েন্টারগুলির দ্বারা রেফারেন্সযুক্ত অবজেক্টগুলি বৈধ রয়েছেন যখন ভেক্টর তাদের কাছে একটি রেফারেন্স রাখে (RAII আইডিয়ামটি ব্যবহার করে স্মার্ট পয়েন্টারগুলি সমস্যার সমাধান করে)।


আমি এটিও নোট করব, আপনি যদি কাঁচা পয়েন্টার ব্যবহার করেন তবে সেগুলি পরিষ্কার করার জন্য আপনি এখন দায়বদ্ধ। এটি করার কোনও ভাল কারণ নেই (আমি যেভাবেই ভাবতে পারি না), আপনার সর্বদা একটি স্মার্ট পয়েন্টার ব্যবহার করা উচিত।
এড এস

1
এটি বলেছিল যে, আপনি স্ট্যান্ড পাত্রে std :: auto_ptr ব্যবহার করবেন না, আরও তথ্যের জন্য: কেন-এটি-ভুল-থেকে-স্ট্যান্ডো-পিটিআর-স্ট্যান্ডার্ড-পাত্রে রয়েছে
অরিজিনাল

24
যেহেতু সি ++ 11, push_backযুক্তিটি কোনও মূল্যসূত্র উল্লেখ হলে অনুলিপিটির পরিবর্তে একটি পদক্ষেপ সম্পাদন করবে। (অবজেক্টগুলি এর সাথে মূল্যবোধের রেফারেন্সগুলিতে রূপান্তরিত হতে পারে std::move()))
এমলাই

2
@tuple_cat আপনার মন্তব্যে "যদি আর্গুমেন্টটি কোনও মূল্যায়ন হয়" বলা উচিত। (যদি যুক্তিটি যথাযথ রেফারেন্স হিসাবে ঘোষিত কোনও সত্তার নাম হয়, তবে যুক্তিটি আসলে লভ্যালু এবং এখান থেকে সরানো হবে না) - "কার্ল নিকোল" এর উত্তরটিতে আমার সম্পাদনাটি পরীক্ষা করুন যা ভুলটি প্রাথমিকভাবে করেছিল
এমএম

নীচে একটি উত্তর রয়েছে তবে এটি পরিষ্কার করে দেওয়া: যেহেতু সি ++ 11 emplace_backকোনও অনুলিপি বা চালনা এড়াতেও ব্যবহার করে (ধারক দ্বারা সরবরাহিত স্থানে অবজেক্ট তৈরি করুন)।
কিশোর

34

হ্যাঁ, std::vectorঅনুলিপি সঞ্চয় করে। কীভাবে vectorআপনার বিষয়গুলির প্রত্যাশিত জীবনের সময়গুলি কী তা জানতে হবে?

আপনি যদি অবজেক্টগুলির মালিকানা স্থানান্তর করতে বা ভাগ করতে চান তবে পয়েন্টার ব্যবহার করুন, সম্ভবত স্মার্ট পয়েন্টারগুলি shared_ptr( বুস্ট বা টিআর 1 তে পাওয়া যায় ) রিসোর্স পরিচালনা সহজ করার জন্য।


3
শেয়ারড_পিটার ব্যবহার করতে শিখুন - তারা আপনি যা চান ঠিক তেমন করে। আমার প্রিয় আইডিয়মটি টাইপডেফ বুস্ট :: শেয়ারড_পিটার <ফু> ফুপপ্রিট; তারপরে FooPtrs এর পাত্রে তৈরি করুন
pm100

3
@ pm100 - জানেন boost::ptr_vector?
ম্যানুয়েল

2
আমি class Foo { typedef boost::shared_ptr<Foo> ptr; };শুধু লিখতে ব্যবহার করতে চাই Foo::ptr
রূপ্ট জোনস

2
@ pm100 - shared_ptrঠিক আগুন নয় এবং ভুলে যাবেন না। দেখুন stackoverflow.com/questions/327573 এবং stackoverflow.com/questions/701456
ড্যানিয়েল Earwicker

2
শেয়ারড_পিটারটি যদি আপনার ভাগ করে নেওয়া মালিকানা ভাল থাকে তবে এটি সাধারণত অতিরিক্ত ব্যবহৃত হয় used স্বতন্ত্রতা যখন স্বতন্ত্র থাকে তখন অনন্য_সিটিআর বা উত্সাহিত স্কোপড_পিটার আরও বেশি বোঝায়।
নেমানজা ত্রিফুনোভিক

28

সি ++ ১১ এর পরে, সমস্ত স্ট্যান্ডার্ড পাত্রে ( std::vector, std::mapইত্যাদি) শব্দচালিত পদার্থকে সমর্থন করে, যার অর্থ আপনি এখন স্ট্যান্ডার্ড পাত্রে মূল্যায়ন করতে পারবেন এবং একটি অনুলিপি এড়াতে পারবেন:

// Example object class.
class object
{
private:
    int             m_val1;
    std::string     m_val2;

public:
    // Constructor for object class.
    object(int val1, std::string &&val2) :
        m_val1(val1),
        m_val2(std::move(val2))
    {

    }
};

std::vector<object> myList;

// #1 Copy into the vector.
object foo1(1, "foo");
myList.push_back(foo1);

// #2 Move into the vector (no copy).
object foo2(1024, "bar");
myList.push_back(std::move(foo2));

// #3 Move temporary into vector (no copy).
myList.push_back(object(453, "baz"));

// #4 Create instance of object directly inside the vector (no copy, no move).
myList.emplace_back(453, "qux");

বিকল্পভাবে আপনি বেশিরভাগ একই প্রভাব পেতে বিভিন্ন স্মার্ট পয়েন্টার ব্যবহার করতে পারেন:

std::unique_ptr উদাহরণ

std::vector<std::unique_ptr<object>> myPtrList;

// #5a unique_ptr can only ever be moved.
auto pFoo = std::make_unique<object>(1, "foo");
myPtrList.push_back(std::move(pFoo));

// #5b unique_ptr can only ever be moved.
myPtrList.push_back(std::make_unique<object>(1, "foo"));

std::shared_ptr উদাহরণ

std::vector<std::shared_ptr<object>> objectPtrList2;

// #6 shared_ptr can be used to retain a copy of the pointer and update both the vector
// value and the local copy simultaneously.
auto pFooShared = std::make_shared<object>(1, "foo");
objectPtrList2.push_back(pFooShared);
// Pointer to object stored in the vector, but pFooShared is still valid.

2
দ্রষ্টব্য যে std::make_unique(বিরক্তিকরভাবে) কেবলমাত্র C ++ 14 এবং উপরের ক্ষেত্রে উপলব্ধ। আপনি যদি এই উদাহরণগুলি সংকলন করতে চান তবে নিশ্চিত হয়ে নিন যে আপনি আপনার সংকলকটিকে সেটির মান অনুসারে সেট করতে বলেছেন।
ল্যারিক্স ডিসিদুয়া

5 এ আপনি auto pFoo =পুনরাবৃত্তি এড়াতে ব্যবহার করতে পারেন ; এবং সমস্ত std::stringক্যাসেটগুলি মুছে ফেলা যায় (স্ট্রিং লিটারাল থেকে অন্তর্ভুক্ত রূপান্তর রয়েছে std::string)
এমএম

2
@ ব্যবহারকারী 465139 make_uniqueসহজেই সি ++ 11 এ প্রয়োগ করা যেতে পারে, সুতরাং সি ++ 11 সংকলকটি আটকে থাকা কারও পক্ষে এটি কেবল সামান্য বিরক্তি
এমএম

1
@ এমএম: আসলেই। এখানে পাঠ্যপুস্তক বাস্তবায়ন:template<typename T, typename... Args> unique_ptr<T> make_unique(Args&&... args) { return unique_ptr<T>{new T{args...}}; }
ল্যারিক্স ডেসিডুয়া

1
@ আনাকিন - হ্যাঁ তাদের করা উচিত, তবে আপনি যদি অনুলিপি করেন তবেই। আপনি যদি এর সাথে ব্যবহার std::move()করেন std::shared_ptrতবে মূল ভাগ করা পয়েন্টারটির মালিকানা ভেক্টরকে দেওয়া হওয়ার পরে এটির পয়েন্টারটি পরিবর্তিত হতে পারে। এখানে দেখুন: coliru.stacked-crooked.com/a/99d4f04f05e5c7f3
কার্ল

15

std :: ভেক্টর সবসময় ভেক্টরে যা কিছু সংরক্ষণ করা হয় তার একটি অনুলিপি তৈরি করে।

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


3
এটি টাইপ উপর নির্ভর করে না। এটি সর্বদা একটি অনুলিপি তৈরি করে। যদি এর পয়েন্টারটি পয়েন্টারটির একটি অনুলিপি তৈরি করে
pm100

তুমি দুজনেই ঠিক আছো প্রযুক্তিগতভাবে, হ্যাঁ, এটি সর্বদা একটি অনুলিপি তৈরি করে। ব্যবহারিকভাবে, আপনি যদি এটিটিকে বস্তুটিতে একটি পয়েন্টারটি পাস করেন তবে এটি পয়েন্টারটি অনুলিপি করে, বস্তুটিকে নয়। নিরাপদে, আপনার একটি উপযুক্ত স্মার্ট পয়েন্টার ব্যবহার করা উচিত।
স্টিভেন সুদিত

1
হ্যাঁ, এটি সর্বদা অনুলিপি করা হয় - তবে, ওপিকে "অবজেক্ট" উল্লেখ করা সম্ভবত সম্ভবত একটি শ্রেণি বা কাঠামো, সুতরাং আমি এটি উল্লেখ করছি যে এটি "অবজেক্ট" অনুলিপি সংজ্ঞার উপর নির্ভর করে কিনা। খারাপভাবে শব্দ করা, যদিও।
রিড কোপসি

3

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


2

সি ++ 11-তে প্রাসঙ্গিক হ'ল emplaceসদস্য ফাংশনগুলির পরিবার, যা আপনাকে পাত্রে স্থানান্তরিত করে বস্তুর মালিকানা হস্তান্তর করতে দেয়।

ব্যবহারের বুদ্ধিমান মত দেখতে হবে

std::vector<Object> objs;

Object l_value_obj { /* initialize */ };
// use object here...

objs.emplace_back(std::move(l_value_obj));

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


0

আপনি যদি কপিগুলি না চান; তারপরে সর্বোত্তম উপায় হ'ল পয়েন্টার ভেক্টর (বা অন্য কোনও কাঠামো যা একই লক্ষ্যে কাজ করে) ব্যবহার করে। আপনি যদি কপিগুলি চান; সরাসরি push_back () ব্যবহার করুন। আপনার অন্য কোনও পছন্দ নেই।


1
পয়েন্টার ভেক্টর সম্পর্কে একটি নোট: ভেক্টর <শেয়ার্ড_প্রেটার <obj>> ভেক্টর <ওজেক্ট *> এর চেয়ে অনেক বেশি নিরাপদ এবং শেয়ারড_পিটার গত বছরের মতো স্ট্যান্ডার্ডের অংশ।
rich.e

-1

এটি খুঁজে বের করতে কেন অনেক ভালগ্রাইন্ড তদন্ত লাগল! কিছু সাধারণ কোড যেমন নিজেকে দিয়ে প্রমাণ করুন

std::vector<std::string> vec;

{
      std::string obj("hello world");
      vec.push_pack(obj);
}

std::cout << vec[0] << std::endl;  

যদি "হ্যালো ওয়ার্ল্ড" মুদ্রিত হয় তবে অবজেক্টটি অবশ্যই অনুলিপি করা উচিত


4
এটি একটি প্রমাণ গঠন করে না। যদি অবজেক্টটি অনুলিপি করা না হয়, তবে আপনার শেষ বিবৃতিটি সংজ্ঞায়িত আচরণ হবে এবং হ্যালো মুদ্রণ করতে পারে
মাদুর

4
সঠিক পরীক্ষাটি সন্নিবেশের পরে দুটির মধ্যে একটির সংশোধন করা হবে। যদি তারা একই বস্তু হয় (যদি ভেক্টর একটি রেফারেন্স সঞ্চিত করে) তবে উভয়ই সংশোধিত হবে।
ফ্রান্সেস্কো দন্ডি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.