ডিজাইন দ্বারা, std::mutex
চলমান বা অনুলিপিযোগ্য নয়। এর অর্থ A
হ'ল মুটেেক্সযুক্ত একটি শ্রেণি কোনও ডিফল্ট মুভ কনস্ট্রাক্টর গ্রহণ করবে না।
আমি এই A
ধরণেরটিকে থ্রেড-নিরাপদ উপায়ে কীভাবে অচল করতে পারি ?
ডিজাইন দ্বারা, std::mutex
চলমান বা অনুলিপিযোগ্য নয়। এর অর্থ A
হ'ল মুটেেক্সযুক্ত একটি শ্রেণি কোনও ডিফল্ট মুভ কনস্ট্রাক্টর গ্রহণ করবে না।
আমি এই A
ধরণেরটিকে থ্রেড-নিরাপদ উপায়ে কীভাবে অচল করতে পারি ?
std::lock_guard
পদ্ধতিটিই স্কোপড।
উত্তর:
কোডটি কিছুটা দিয়ে শুরু করা যাক:
class A
{
using MutexType = std::mutex;
using ReadLock = std::unique_lock<MutexType>;
using WriteLock = std::unique_lock<MutexType>;
mutable MutexType mut_;
std::string field1_;
std::string field2_;
public:
...
আমি সেখানে কিছু পরিবর্তে পরামর্শমূলক ধরণের এলিয়াস রেখেছি যে আমরা সত্যই সি ++ 11 তে সুবিধা নেব না, তবে সি ++ 14 এ আরও দরকারী হয়ে উঠব। ধৈর্য ধরুন, আমরা সেখানে পৌঁছে যাব।
আপনার প্রশ্নটি এখানে ফোটে:
এই ক্লাসের জন্য আমি কীভাবে মুভ কনস্ট্রাক্টর এবং মুভ এসাইনমেন্ট অপারেটর লিখব?
আমরা মুভ কনস্ট্রাক্টর দিয়ে শুরু করব।
কনস্ট্রাক্টর সরান
নোট করুন যে সদস্যটি mutex
করা হয়েছে mutable
। সরানো সদস্যদের জন্য কড়া কথা বলতে এটি প্রয়োজনীয় নয়, তবে আমি ধরে নিচ্ছি আপনিও অনুলিপি সদস্যদের চান want যদি এটি না হয় তবে মিউটেক্স তৈরি করার দরকার নেই mutable
।
নির্মাণের সময় A
, আপনাকে লক করার দরকার নেই this->mut_
। তবে আপনি যে mut_
পদক্ষেপটি তৈরি করছেন তা লক করা দরকার (সরানো বা অনুলিপি)। এটি এর মতো করা যেতে পারে:
A(A&& a)
{
WriteLock rhs_lk(a.mut_);
field1_ = std::move(a.field1_);
field2_ = std::move(a.field2_);
}
নোট করুন যে আমাদের this
প্রথমে সদস্যদের ডিফল্টরূপে নির্মাণ করতে হয়েছিল এবং তারপরে a.mut_
লক হওয়ার পরে কেবল তাদের মান নির্ধারণ করতে হয়েছিল ।
বরাদ্দকরণ
মুভ অ্যাসাইনমেন্ট অপারেটর যথেষ্ট পরিমাণে জটিল কারণ আপনি জানেন না যে অন্য কোনও থ্রেড অ্যাসাইনমেন্ট এক্সপ্রেশনটির lhs বা rh হয় অ্যাক্সেস করছে কিনা। এবং সাধারণভাবে, আপনাকে নিম্নলিখিত পরিস্থিতিতে রক্ষা করতে হবে:
// Thread 1
x = std::move(y);
// Thread 2
y = std::move(x);
এখানে মুভ অ্যাসাইনমেন্ট অপারেটর যা উপরের দৃশ্যকে সঠিকভাবে রক্ষা করে:
A& operator=(A&& a)
{
if (this != &a)
{
WriteLock lhs_lk(mut_, std::defer_lock);
WriteLock rhs_lk(a.mut_, std::defer_lock);
std::lock(lhs_lk, rhs_lk);
field1_ = std::move(a.field1_);
field2_ = std::move(a.field2_);
}
return *this;
}
নোট করুন যে একটিকে অবশ্যই std::lock(m1, m2)
একের পর এক লক করার পরিবর্তে দুটি মুটেক্সকে লক করতে ব্যবহার করতে হবে । আপনি যদি একে একে একে একে লক করে রাখেন, তারপরে যখন দুটি থ্রেড দুটি উপরে উল্লিখিত হিসাবে দুটি বিপরীতে ক্রম স্থির করে, আপনি একটি অচলাবস্থা পেতে পারেন। বিন্দুstd::lock
হ'ল সেই অচলাবস্থা এড়ানো।
অনুলিপি নির্মাণকারী
আপনি অনুলিপি সদস্যদের সম্পর্কে জিজ্ঞাসা করেননি, তবে আমরা এখনই তাদের সম্পর্কে ভালভাবে কথা বলতে পারি (যদি আপনি না হন তবে কারওর প্রয়োজন হবে)।
A(const A& a)
{
ReadLock rhs_lk(a.mut_);
field1_ = a.field1_;
field2_ = a.field2_;
}
অনুলিপি কনস্ট্রাক্টরটিকে অনেকটা মুভ কনস্ট্রাক্টরের মতো দেখতে ReadLock
পাওয়া যায় পরিবর্তে এর পরিবর্তে ওরফে ব্যবহার করা হয় WriteLock
। বর্তমানে এই দুটি ওরফেstd::unique_lock<std::mutex>
এবং তাই এটি সত্যিকার অর্থে কোনও পার্থক্য করে না।
তবে সি ++ এ, আপনার এই কথাটি বলার বিকল্প থাকবে:
using MutexType = std::shared_timed_mutex;
using ReadLock = std::shared_lock<MutexType>;
using WriteLock = std::unique_lock<MutexType>;
এটি একটি অপ্টিমাইজেশন হতে পারে, তবে অবশ্যই না। এটি কিনা তা নির্ধারণ করতে আপনাকে পরিমাপ করতে হবে। তবে এই পরিবর্তনের সাথে সাথে একসাথে একাধিক থ্রেডে একই আরএইচএস থেকে কন্ট্রাক্ট অনুলিপি করা যায় । সি ++ 11 সমাধান আপনাকে এই ধরনের থ্রেডগুলিকে অনুক্রমিক করে তুলতে বাধ্য করে, যদিও আরএইচএস পরিবর্তন করা হচ্ছে না।
অ্যাসাইনমেন্ট কপি করুন
সম্পূর্ণতার জন্য, এখানে অনুলিপি অ্যাসাইনমেন্ট অপারেটর, যা অন্য সমস্ত কিছু পড়ার পরে মোটামুটি স্ব-বর্ণনামূলক হওয়া উচিত:
A& operator=(const A& a)
{
if (this != &a)
{
WriteLock lhs_lk(mut_, std::defer_lock);
ReadLock rhs_lk(a.mut_, std::defer_lock);
std::lock(lhs_lk, rhs_lk);
field1_ = a.field1_;
field2_ = a.field2_;
}
return *this;
}
এবং ইত্যাদি.
A
যদি আপনি একাধিক থ্রেডগুলি একবারে কল করতে সক্ষম হন বলে আশা করেন তবে অন্য যে কোনও সদস্য বা ফ্রি ফাংশনগুলির রাজ্যে অ্যাক্সেস রয়েছে সেগুলিও সুরক্ষিত হওয়া দরকার। উদাহরণস্বরূপ, এখানে swap
:
friend void swap(A& x, A& y)
{
if (&x != &y)
{
WriteLock lhs_lk(x.mut_, std::defer_lock);
WriteLock rhs_lk(y.mut_, std::defer_lock);
std::lock(lhs_lk, rhs_lk);
using std::swap;
swap(x.field1_, y.field1_);
swap(x.field2_, y.field2_);
}
}
মনে রাখবেন যে আপনি যদি কেবল std::swap
কাজটি করার উপর নির্ভর করেন তবে লকিংটি ভুল দানাদারতায় থাকবে, std::swap
অভ্যন্তরীণভাবে সঞ্চালিত তিনটি চালকের মধ্যে লকিং এবং আনলক হবে।
প্রকৃতপক্ষে, চিন্তাভাবনা swap
আপনাকে এপিআই সম্পর্কে অন্তর্দৃষ্টি দিতে পারে আপনার "থ্রেড-সেফ" সরবরাহের প্রয়োজন হতে পারে A
যা সাধারণত "লকিং গ্রানুলারিটি" ইস্যুর কারণে "নন-থ্রেড-সেফ" এপিআই থেকে আলাদা হবে।
"স্ব-অদলবদল" থেকে রক্ষা করার প্রয়োজনীয়তাটিও নোট করুন। "স্ব-অদলবদল" এর কোনও অপশন হওয়া উচিত। স্বতঃপরীক্ষা ব্যতীত পুনরাবৃত্তভাবে একই মিটেক্সটিকে লক করা হবে। এই ব্যবহার করে স্ব-চেক ছাড়া সমাধান করা যেতে পারে std::recursive_mutex
জন্যMutexType
।
হালনাগাদ
ইয়াক্ক নীচের মন্তব্যে অনুলিপিটি কপির এবং মুভ কনস্ট্রাক্টরগুলিতে ডিফল্ট নির্মাণের বিষয়ে অসন্তুষ্ট (এবং তার একটি বক্তব্য রয়েছে)। আপনি যদি এই সমস্যাটি সম্পর্কে দৃ strongly়ভাবে অনুভব করেন, যাতে আপনি এটির উপর মেমরি ব্যয় করতে ইচ্ছুক হন, আপনি এটিকে এড়াতে পারেন:
ডেটা সদস্য হিসাবে আপনার প্রয়োজন মতো লক টাইপ যুক্ত করুন। এই সদস্যদের অবশ্যই সুরক্ষিত থাকা ডেটার আগে আসতে হবে:
mutable MutexType mut_;
ReadLock read_lock_;
WriteLock write_lock_;
// ... other data members ...
এবং তারপরে কনস্ট্রাক্টরগুলিতে (যেমন অনুলিপি নির্মাণকারী) এটি করুন:
A(const A& a)
: read_lock_(a.mut_)
, field1_(a.field1_)
, field2_(a.field2_)
{
read_lock_.unlock();
}
ওফস, ইয়াক্ক আমার এই আপডেটটি সম্পূর্ণ করার সুযোগ পাওয়ার আগে তার মন্তব্য মুছে ফেলল। তবে এই ইস্যুটি চাপ দেওয়ার এবং এই উত্তরের সমাধান পাওয়ার জন্য তিনি creditণ পাওয়ার যোগ্য।
আপডেট 2
এবং ডাইপ এই ভাল পরামর্শ নিয়ে আসে:
A(const A& a)
: A(a, ReadLock(a.mut_))
{}
private:
A(const A& a, ReadLock rhs_lk)
: field1_(a.field1_)
, field2_(a.field2_)
{}
mutexes
শ্রেণির ধরণগুলি স্থাপন করা "একটি সত্য উপায়" নয়। এটি সরঞ্জামবাক্সের একটি সরঞ্জাম এবং আপনি যদি এটি ব্যবহার করতে চান তবে এটি।
এর জবাব দেওয়ার মতো সুন্দর, পরিষ্কার, সহজ উপায় বলে মনে হচ্ছে না - আন্তোনের সমাধান আমি মনে করি সঠিক, তবে এটির তাত্পর্যপূর্ণভাবে বিতর্কযোগ্য, যদি এর চেয়ে ভাল উত্তর না আসে তবে আমি এই ধরণের ক্লাসটি স্তূপের উপরে রাখার এবং এটির যত্ন নেওয়ার পরামর্শ দিই এর মাধ্যমে std::unique_ptr
:
auto a = std::make_unique<A>();
এটি এখন পুরোপুরি চলমান টাইপ এবং অভ্যন্তরীণ মিউটেক্সের সাথে তালুতে থাকা যে কেউ পদক্ষেপ নেওয়ার পরেও সে নিরাপদ, এমনকি এটি বিতর্কযোগ্য হলেও এটি করা ভাল যে এটি করা ভাল?
আপনার যদি কপির শব্দার্থবিদ্যা প্রয়োজন কেবল ব্যবহার করুন just
auto a2 = std::make_shared<A>();
এটি একটি উল্টো উত্তর। প্রকারের ভিত্তি হিসাবে এম্বেড করার পরিবর্তে "এই বিষয়গুলিকে সিঙ্ক্রোনাইজ করা দরকার" পরিবর্তে এটির অধীনে ইনজেক্ট করুন কোনও প্রকারের ।
আপনি একটি সিঙ্ক্রোনাইজড বস্তুর সাথে খুব আলাদাভাবে ডিল করেন। একটি বড় সমস্যা হ'ল ডেডলকগুলি (একাধিক বস্তু লক করা) সম্পর্কে আপনাকে চিন্তা করতে হবে। এটি মূলত কখনই আপনার "কোনও সামগ্রীর ডিফল্ট সংস্করণ" হওয়া উচিত নয়: সিঙ্ক্রোনাইজ করা অবজেক্টগুলি সেই বিষয়গুলির জন্য যা বিতর্কযুক্ত হবে এবং আপনার লক্ষ্যটি থ্রেডগুলির মধ্যে বিবাদকে হ্রাস করতে হবে, গালিগাছার নীচে ঝাড়ু নয়।
তবে অবজেক্টগুলি সিঙ্ক্রোনাইজ করা এখনও কার্যকর। একটি সিঙ্ক্রোনাইজার থেকে উত্তরাধিকার সূত্রে পরিবর্তে, আমরা এমন একটি শ্রেণি লিখতে পারি যা একটি সিংক্রোনাইজেশনে একটি স্বেচ্ছাসেবী প্রকারকে আবৃত করে। ব্যবহারকারীদের এখন বস্তুটির ক্রিয়াকলাপ করতে কয়েকটি হুপের মধ্য দিয়ে ঝাঁপিয়ে পড়তে হবে যেটি এটি সিঙ্ক্রোনাইজ করা হয়েছে, তবে তারা বস্তুটিতে কিছু হ্যান্ড-কোডড সীমিত সংখ্যায় সীমাবদ্ধ নয়। তারা বস্তুর উপর একাধিক ক্রিয়াকে এক হিসাবে রচনা করতে পারে, বা একাধিক বস্তুর উপর একটি ক্রিয়াকলাপ করতে পারে।
একটি স্বেচ্ছাসেবী টাইপের চারপাশে একটি সিঙ্ক্রোনাইজ করা মোড়ক দেওয়া T
:
template<class T>
struct synchronized {
template<class F>
auto read(F&& f) const&->std::result_of_t<F(T const&)> {
return access(std::forward<F>(f), *this);
}
template<class F>
auto read(F&& f) &&->std::result_of_t<F(T&&)> {
return access(std::forward<F>(f), std::move(*this));
}
template<class F>
auto write(F&& f)->std::result_of_t<F(T&)> {
return access(std::forward<F>(f), *this);
}
// uses `const` ness of Syncs to determine access:
template<class F, class... Syncs>
friend auto access( F&& f, Syncs&&... syncs )->
std::result_of_t< F(decltype(std::forward<Syncs>(syncs).t)...) >
{
return access2( std::index_sequence_for<Syncs...>{}, std::forward<F>(f), std::forward<Syncs>(syncs)... );
};
synchronized(synchronized const& o):t(o.read([](T const&o){return o;})){}
synchronized(synchronized && o):t(std::move(o).read([](T&&o){return std::move(o);})){}
// special member functions:
synchronized( T & o ):t(o) {}
synchronized( T const& o ):t(o) {}
synchronized( T && o ):t(std::move(o)) {}
synchronized( T const&& o ):t(std::move(o)) {}
synchronized& operator=(T const& o) {
write([&](T& t){
t=o;
});
return *this;
}
synchronized& operator=(T && o) {
write([&](T& t){
t=std::move(o);
});
return *this;
}
private:
template<class X, class S>
static auto smart_lock(S const& s) {
return std::shared_lock< std::shared_timed_mutex >(s.m, X{});
}
template<class X, class S>
static auto smart_lock(S& s) {
return std::unique_lock< std::shared_timed_mutex >(s.m, X{});
}
template<class L>
static void lock(L& lockable) {
lockable.lock();
}
template<class...Ls>
static void lock(Ls&... lockable) {
std::lock( lockable... );
}
template<size_t...Is, class F, class...Syncs>
friend auto access2( std::index_sequence<Is...>, F&&f, Syncs&&...syncs)->
std::result_of_t< F(decltype(std::forward<Syncs>(syncs).t)...) >
{
auto locks = std::make_tuple( smart_lock<std::defer_lock_t>(syncs)... );
lock( std::get<Is>(locks)... );
return std::forward<F>(f)(std::forward<Syncs>(syncs).t ...);
}
mutable std::shared_timed_mutex m;
T t;
};
template<class T>
synchronized< T > sync( T&& t ) {
return {std::forward<T>(t)};
}
সি ++ 14 এবং সি ++ 1z বৈশিষ্ট্য অন্তর্ভুক্ত।
এটি ধরে নিয়েছে যে const
অপারেশনগুলি একাধিক-পাঠক নিরাপদ (যা std
ধারক ধারনা করে)।
ব্যবহার দেখে মনে হচ্ছে:
synchronized<int> x = 7;
x.read([&](auto&& v){
std::cout << v << '\n';
});
int
সিঙ্ক্রোনাইজড অ্যাক্সেস সহ একটি জন্য ।
আমি থাকার বিরুদ্ধে পরামর্শ দেব synchronized(synchronized const&)
। এটি খুব কমই প্রয়োজন হয়।
আপনার যা দরকার তা যদি synchronized(synchronized const&)
আমি প্রতিস্থাপন করতে প্রলুব্ধ করা চাই T t;
সঙ্গে std::aligned_storage
, ম্যানুয়াল বসানো নির্মাণ, যার ফলে এবং ম্যানুয়াল ধ্বংস না। যা সঠিক জীবনকাল পরিচালনা করতে দেয়।
এটি বাদ দিয়ে আমরা উত্সটি অনুলিপি করতে পারি T
, তারপরে এটি পড়তে পারি:
synchronized(synchronized const& o):
t(o.read(
[](T const&o){return o;})
)
{}
synchronized(synchronized && o):
t(std::move(o).read(
[](T&&o){return std::move(o);})
)
{}
নিয়োগের জন্য:
synchronized& operator=(synchronized const& o) {
access([](T& lhs, T const& rhs){
lhs = rhs;
}, *this, o);
return *this;
}
synchronized& operator=(synchronized && o) {
access([](T& lhs, T&& rhs){
lhs = std::move(rhs);
}, *this, std::move(o));
return *this;
}
friend void swap(synchronized& lhs, synchronized& rhs) {
access([](T& lhs, T& rhs){
using std::swap;
swap(lhs, rhs);
}, *this, o);
}
স্থাপনা এবং সারিবদ্ধ স্টোরেজ সংস্করণগুলি কিছুটা বার্তাবহ। সর্বাধিক অ্যাক্সেস t
সদস্য ফাংশন দ্বারা প্রতিস্থাপন করা হবে T&t()
এবং T const&t()const
, যেখানে আপনাকে কিছু হুপ দিয়ে যেতে হবে সেখানে ব্যতীত।
করা হলে synchronized
শ্রেণীর অংশ পরিবর্তে একটি মোড়কের, সব আমরা নিশ্চিত করতে হবে যে বর্গ অভ্যন্তরীণভাবে শ্রদ্ধা const
হচ্ছে একাধিক-রিডার, এবং একটি একক থ্রেডেড পদ্ধতিতে লিখতে।
ইন বিরল ক্ষেত্রে আমরা একটি সিঙ্ক্রোনাইজ উদাহরণস্বরূপ প্রয়োজন, আমরা উপরোক্ত মত হুপ্স মাধ্যমে তিড়িং লাফ।
উপরের যে কোনও টাইপের জন্য ক্ষমা চাইছি। সম্ভবত কিছু আছে।
উপরের দিকের একটি সুবিধা হ'ল হ'ল synchronized
হার্ড-কোড না করে অবজেক্টগুলিতে (একই ধরণের) স্বেচ্ছাসেবক ক্রিয়াকলাপ একসাথে কাজ করে। বন্ধুত্বের ঘোষণায় যুক্ত করুন এবং synchronized
একাধিক ধরণের n-ary অবজেক্টগুলি একসাথে কাজ করতে পারে। আমি সরাতে থাকতে পারে access
সেই ক্ষেত্রে জমিদার conficts সঙ্গে মোকাবিলা করার জন্য একটি ইনলাইন বন্ধু হবার শেষ হয়ে এসেছে।
মুডেক্সেস এবং সি ++ মুভ শব্দার্থক ব্যবহার থ্রেডগুলির মধ্যে ডেটা নিরাপদে এবং দক্ষতার সাথে স্থানান্তর করার একটি দুর্দান্ত উপায়।
এমন একটি 'প্রযোজক' থ্রেডের কল্পনা করুন যা স্ট্রিংগুলির ব্যাচ তৈরি করে এবং তাদের (এক বা একাধিক) গ্রাহকদের সরবরাহ করে। এই ব্যাচগুলি (সম্ভাব্য বৃহত) std::vector<std::string>
অবজেক্টযুক্ত কোনও বস্তু দ্বারা প্রতিনিধিত্ব করা যেতে পারে । আমরা সম্পূর্ণরূপে অপ্রয়োজনীয় সদৃশ ছাড়াই ve ভেক্টরগুলির অভ্যন্তরীণ অবস্থাকে তাদের গ্রাহকদের মধ্যে স্থানান্তরিত করতে চাই।
আপনি কেবলমাত্র মুউটেক্সকে অবজেক্টের অংশ হিসাবে নয়, বস্তুর অংশ হিসাবে চিনতে পারেন। অর্থাত্ আপনি মুটেক্সটি সরাতে চান না।
আপনাকে কী লক করা দরকার তা নির্ভর করে আপনার অ্যালগরিদম বা কীভাবে আপনার অবজেক্টগুলি সাধারণীকরণ করা হয় এবং আপনি কত ধরণের ব্যবহারের অনুমতি দেন।
যদি আপনি কেবল কোনও ভাগ করা রাজ্য 'প্রযোজক' অবজেক্ট থেকে কোনও থ্রেড-লোকাল 'গ্রাহক' অবজেক্টে চলে যান তবে আপনি কেবলমাত্র অবজেক্ট থেকে স্থানান্তরিত লক করা ঠিক আছে ।
যদি এটি আরও সাধারণ নকশা হয় তবে আপনার উভয়কেই লক করতে হবে। এই জাতীয় ক্ষেত্রে আপনাকে তখন ডেড-লকিং বিবেচনা করা উচিত।
যদি এটি কোনও সম্ভাব্য সমস্যা হয় তবে std::lock()
একটি অচলাবস্থামুক্ত পদ্ধতিতে উভয় মিটেক্সে লক সংগ্রহ করতে ব্যবহার করুন।
http://en.cppreferences.com/w/cpp/thread/lock
একটি চূড়ান্ত নোট হিসাবে আপনার মুভ শব্দার্থবিজ্ঞান বুঝতে পেরেছেন তা নিশ্চিত করা দরকার। মনে রাখবেন যে অবজেক্ট থেকে সরানো একটি বৈধ তবে অজানা অবস্থায় রয়েছে। এটি সম্পূর্ণরূপে সম্ভব যে কোনও থ্রেড মুভটি সম্পাদন করছে না এমন কোনও বৈধ তবে অজানা অবস্থাটি খুঁজে পেতে পারে যখন অবজেক্ট থেকে সরানো অ্যাক্সেসের চেষ্টা করার একটি বৈধ কারণ রয়েছে।
আবার আমার প্রযোজক কেবল স্ট্রিং বেজে যাচ্ছে এবং গ্রাহক পুরো লোডটি হরণ করছেন। সেক্ষেত্রে প্রতিবার প্রযোজক ভেক্টরে যুক্ত হওয়ার চেষ্টা করলে ভেক্টরটি খালি বা খালি পাওয়া যায়।
সংক্ষেপে যদি অবজেক্ট থেকে সরানো সম্ভাব্য একযোগে অ্যাক্সেসের লেখার পরিমাণ থাকে তবে সম্ভবত এটি ঠিক আছে। যদি এটি কোনও পঠনের সমান হয় তবে স্বেচ্ছাসেবী অবস্থায় পড়া কেন ঠিক আছে তা নিয়ে ভাবেন।
প্রথমত, আপনি যদি কোনও মিউটেক্সযুক্ত কোনও বস্তু সরাতে চান তবে আপনার ডিজাইনের সাথে অবশ্যই কিছু ভুল হতে হবে।
তবে আপনি যদি যাইহোক এটি করার সিদ্ধান্ত নেন তবে আপনাকে মুভ কনস্ট্রাক্টরে একটি নতুন মিটেক্স তৈরি করতে হবে, উদাহরণস্বরূপ:
// movable
struct B{};
class A {
B b;
std::mutex m;
public:
A(A&& a)
: b(std::move(a.b))
// m is default-initialized.
{
}
};
এটি থ্রেড-সেফ, কারণ মুভ কনস্ট্রাক্টর নিরাপদে ধরে নিতে পারে যে এর যুক্তি অন্য কোথাও ব্যবহার করা হয়নি, সুতরাং আর্গুমেন্টের লকিংয়ের প্রয়োজন নেই।
A a; A a2(std::move(a)); do some stuff with a
।
new
উদাহরণটি আপ করার এবং এটিতে রাখার প্রস্তাব দিই std::unique_ptr
- এটি পরিষ্কার বলে মনে হচ্ছে এবং বিভ্রান্তির কারণ হওয়ার সম্ভাবনা নেই। ভাল প্রশ্ন.