আমি কীভাবে একটি ফাংশনে স্ট্যান্ড :: অনন্য_পিটার পাস করতে পারি?


97

আমি কীভাবে std::unique_ptrকোনও কার্যক্রমে পাস করতে পারি ? আসুন আমাদের নীচের ক্লাসটি বলুন:

class A
{
public:
    A(int val)
    {
        _val = val;
    }

    int GetVal() { return _val; }
private:
    int _val;
};

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

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);

    return 0;
}

আমি কেন std::unique_ptrএকটি ফাংশনে প্রবেশ করতে পারি না ? নিশ্চয় এটি নির্মাণের প্রাথমিক উদ্দেশ্য? অথবা সি ++ কমিটি আমার কাছে কাঁচা সি-স্টাইল পয়েন্টারগুলিতে ফিরে এসে এটি এভাবে পাস করার ইচ্ছা করেছিল:

MyFunc(&(*ptr)); 

এবং সবচেয়ে আশ্চর্যের বিষয়, এটি কেন পাস করার এটি একটি সঠিক উপায়? এটি মারাত্মকভাবে বেমানান বলে মনে হচ্ছে:

MyFunc(unique_ptr<A>(new A(1234)));

7
কাঁচা সি-স্টাইল পয়েন্টারগুলিতে যতক্ষণ না তারা মালিকানাধীন কাঁচা পয়েন্টার হয় ততক্ষণ "পিছিয়ে পড়া" তেমন কোনও সমস্যা নেই। আপনি 'ptr.get ()' লিখতে পছন্দ করতে পারেন। যদিও, আপনার যদি অযোগ্যতা প্রয়োজন না হয় তবে একটি রেফারেন্স পছন্দ করা হবে।
ক্রিস ড্রিউ

উত্তর:


142

এখানে মূলত দুটি বিকল্প রয়েছে:

রেফারেন্স সহ স্মার্ট পয়েন্টারটি পাস করুন

void MyFunc(unique_ptr<A> & arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);
}

ফাংশন আর্গুমেন্টে স্মার্ট পয়েন্টারটি সরান

মনে রাখবেন যে এই ক্ষেত্রে, দৃ !়তা রাখা হবে!

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(move(ptr));
    assert(ptr == nullptr)
}

@ ভার্মিলিয়নআজুরি: আপনি যে বৈশিষ্ট্যটির কথা উল্লেখ করছেন তা সাধারণত অনার্যযোগ্য, অনন্য নয়।
বিল লিঞ্চ

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

7
আপনার কেবলমাত্র unique_ptrরেফারেন্স দিয়ে একটি পাস করতে হবে যদি ফাংশন এটি থেকে সরে বা না-যেতে পারে। এবং তারপরে এটি একটি মূল রেফারেন্স হওয়া উচিত। কোনও সামগ্রীর মালিকানা সংক্রান্ত শব্দার্থবিজ্ঞানের কোনও প্রয়োজন ছাড়াই পর্যবেক্ষণ করতে, A const&বা এর মতো একটি রেফারেন্স ব্যবহার করুন A&
পোটোসওয়টার

12
সিপিসকন ২০১৪-তে হার্ব সটারস আলাপ শুনুন unique অনন্য_সেপ্টর <> এর উল্লেখ রেফারেন্স দেওয়ার জন্য তিনি দৃ strongly়ভাবে নিরুৎসাহিত করেন। সারমর্মটি হ'ল, আপনি যখন মালিকানার সাথে লেনদেন করবেন তখন আপনার কেবল অনন্য_প্ট্রি <> বা শেয়ারড_সিপি <> এর মতো স্মার্ট পয়েন্টার ব্যবহার করা উচিত। Www.youtube.com/watch?v=xnqTKD8uD64
schorsch_76

4
@ ফুরিহর: ptrএই পদক্ষেপের পরে এর মূল্য কী তা দেখানোর এটি একটি উপায় ।
বিল লিঞ্চ

26

আপনি এটি মান দিয়ে যাচ্ছেন যা একটি অনুলিপি তৈরি করে বোঝায়। এটি খুব অনন্য হবে না, তাই না?

আপনি মানটি সরাতে পারেন, তবে এটি ফাংশনে তার অবজেক্টের মালিকানা এবং তার জীবদ্দশার নিয়ন্ত্রণকে বোঝায়।

যদি মাইফুঙ্কের কাছে কলটির আজীবন অবজেক্টের জীবদ্দশার অস্তিত্বের নিশ্চয়তা দেওয়া থাকে তবে কেবল একটি কাঁচা পয়েন্টারটি দিয়ে দিন ptr.get()


17

আমি কেন unique_ptrএকটি ফাংশনে প্রবেশ করতে পারি না ?

আপনি এটি করতে পারবেন না কারণ unique_ptrএকটি মুভ কনস্ট্রাক্টর আছে তবে একটি অনুলিপি নির্মাণকারী নেই। স্ট্যান্ডার্ড অনুযায়ী, যখন একটি মুভ কনস্ট্রাক্টর সংজ্ঞায়িত করা হয় তবে একটি অনুলিপি কনস্ট্রাক্টর সংজ্ঞায়িত হয় না, অনুলিপি নির্মাণকারী মুছে ফেলা হয়।

12.8 শ্রেণি অবজেক্টগুলি অনুলিপি করা এবং চলমান

...

7 যদি শ্রেণি সংজ্ঞাটি স্পষ্টভাবে একটি অনুলিপি নির্মাণকারীকে ঘোষণা না করে তবে একটি স্পষ্টভাবে ঘোষণা করা হয়। যদি শ্রেণি সংজ্ঞাটি একটি মুভ কনস্ট্রাক্টর বা মুভ অ্যাসাইনমেন্ট অপারেটর হিসাবে ঘোষণা করে, তবে স্পষ্টভাবে ঘোষিত অনুলিপি নির্ধারক মুছে ফেলা হিসাবে সংজ্ঞায়িত হয়;

আপনি unique_ptrব্যবহার করে ফাংশনটি পাস করতে পারেন :

void MyFunc(std::unique_ptr<A>& arg)
{
    cout << arg->GetVal() << endl;
}

এবং এটি আপনার মতো ব্যবহার করুন:

বা

void MyFunc(std::unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

এবং এটি ব্যবহার করুন:

std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234));
MyFunc(std::move(ptr));

গুরুত্বপূর্ণ তথ্য

দয়া করে মনে রাখবেন যে আপনি যদি দ্বিতীয় পদ্ধতিটি ব্যবহার করেন ptrতবে কল করার পরে std::move(ptr)রিটার্নের পরে পয়েন্টারের মালিকানা নেই ।

void MyFunc(std::unique_ptr<A>&& arg)void MyFunc(std::unique_ptr<A>& arg)উভয় উল্লেখ হিসাবে একই প্রভাব হবে ।

প্রথম ক্ষেত্রে, ptrকল করার পরেও পয়েন্টারের মালিকানা রয়েছে MyFunc


5

যেমন MyFuncমালিকানা গ্রহণ করে না, তত ভাল হয়:

void MyFunc(const A* arg)
{
    assert(arg != nullptr); // or throw ?
    cout << arg->GetVal() << endl;
}

বা আরও ভাল

void MyFunc(const A& arg)
{
    cout << arg.GetVal() << endl;
}

আপনি যদি সত্যিই মালিকানা নিতে চান তবে আপনাকে আপনার সংস্থানটি স্থানান্তর করতে হবে:

std::unique_ptr<A> ptr = std::make_unique<A>(1234);
MyFunc(std::move(ptr));

অথবা সরাসরি একটি আর-মূল্য উল্লেখ প্রেরণ করুন:

MyFunc(std::make_unique<A>(1234));

std::unique_ptr গ্যারান্টির উদ্দেশ্যে কেবলমাত্র একজন মালিক থাকার উদ্দেশ্যে অনুলিপি নেই।


এই উত্তরটি অনুপস্থিত যে মাইফাঙ্কের কলটি আপনার প্রথম দুটি ক্ষেত্রে দেখা যাচ্ছে। নিশ্চিত না আপনি যদি ব্যবহার করছেন ptr.get()বা কেবল ptrফাংশনে প্রবেশ করছেন?
টেললোস্টাইন

MyFuncআর-মান রেফারেন্সটি পাস করার উদ্দেশ্যে স্বাক্ষরটি কী ?
জেমস হিরশর্ন

@ জামেসহির্সকর্ন: void MyFunc(A&& arg)আর-মান রেফারেন্স নেয় ...
জারোড 42

@ Jarod42 যে আমি যা অনুমিত, কিন্তু সঙ্গে typedef int A[], MyFunc(std::make_unique<A>(N))ত্রুটি:: কম্পাইলার এরর দেয় ধরনের রেফারেন্স অবৈধ আরম্ভের 'INT (&&) []' ধরনের অভিব্যক্তি থেকে 'এসটিডি ::: _ MakeUniq <int- এ []> :: __ অ্যারে' { ওরফে 'এসটিডি :: অনন্য_প্রেটার <ইন [], স্টাডি :: ডিফল্ট_ডিলিট <ইন []]>' g++ -std=gnu++11recent সাম্প্রতিক কি যথেষ্ট?
জেমস হিরশর্ন

@ জারোড 42 আমি আইডিয়োন সহ সি ++ 14 এর ব্যর্থতা নিশ্চিত করেছি: আইডোন
জেমস হিরশর্ন

4

আমি কেন unique_ptrএকটি ফাংশনে প্রবেশ করতে পারি না ?

আপনি পারবেন, তবে অনুলিপি দ্বারা নয় - কারণ std::unique_ptr<>অনুলিপি-গঠনযোগ্য নয়।

নিশ্চয় এটি নির্মাণের প্রাথমিক উদ্দেশ্য?

অন্যান্য বিষয়গুলির মধ্যে, অনন্য মালিকানা (বিরোধিতা হিসাবে ) std::unique_ptr<>অনির্দিষ্টভাবে চিহ্নিত করার জন্য তৈরি করা হয়েছে ।std::shared_ptr<>

এবং সবচেয়ে আশ্চর্যের বিষয়, এটি কেন পাস করার এটি একটি সঠিক উপায়?

কারণ সেক্ষেত্রে কোনও অনুলিপি-নির্মাণ নেই।


আপনার উত্তরের জন্য ধন্যবাদ. মাত্র আগ্রহের বাইরে, আপনি কী ব্যাখ্যা করতে পারবেন কেন এটি পাসের শেষ উপায়টি অনুলিপি নির্মাণকারী ব্যবহার করছে না? আমি ভাবতাম যে অনন্য_পট্রের কনস্ট্রাক্টর ব্যবহারটি স্ট্যাকের উপর একটি উদাহরণ তৈরি করবে, যা কপি কনস্ট্রাক্টর ব্যবহার করে মাইফ্যাঙ্ক () এর পক্ষে যুক্তিতে অনুলিপি হবে? যদিও আমি স্বীকার করি এই অঞ্চলটিতে আমার স্মৃতিচিহ্নটি কিছুটা অস্পষ্ট।
ব্যবহারকারী 3690202

4
এটি একটি মূল্য হিসাবে, পরিবর্তে মুভ-কনস্ট্রাক্টর বলা হয়। যদিও আপনার সংকলক অবশ্যই এটিকে যাইহোক অপ্টিমাইজ করবে।
নিলক

0

যেহেতু unique_ptrঅনন্য মালিকানার জন্য, আপনি যদি এটি যুক্তির চেষ্টা হিসাবে পাস করতে চান

MyFunc(move(ptr));

তবে এর পরে ptrইন-এর অবস্থা mainহবে nullptr


4
"অপরিজ্ঞাপিত হবে" - না, এটি বাতিল হবে, বা unique_ptrবরং অকেজো হবে।
টিসি

0

std::unique_ptr<T>কোনও ফাংশনের মান হিসাবে পাস করা কাজ করছে না কারণ আপনারা যেমন উল্লেখ করেছেন, unique_ptrঅনুলিপিযোগ্য নয়।

এই সম্পর্কে কি?

std::unique_ptr<T> getSomething()
{
   auto ptr = std::make_unique<T>();
   return ptr;
}

এই কোড কাজ করছে


যদি সেই কোডটি কাজ করে তবে আমার অনুমানটি হ'ল এটি অনন্য_পিটারটি অনুলিপি করছে না, তবে বাস্তবে এটি সরানোর জন্য পদক্ষেপ পদার্থ ব্যবহার করে।
ব্যবহারকারী 3690202

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