লিগ্যাসি কোডের কয়েকটি টুকরোতে আমার একটি মোড়ক রয়েছে।
class A{
L* impl_; // the legacy object has to be in the heap, could be also unique_ptr
A(A const&) = delete;
L* duplicate(){L* ret; legacy_duplicate(impl_, &L); return ret;}
... // proper resource management here
};
এই লিগ্যাসি কোডে, কোন ফাংশনটি "অনুলিপি" দেয় কোনও বস্তুটি থ্রেড নিরাপদ নয় (একই প্রথম যুক্তির দিকে আহ্বান করার সময়), সুতরাং এটি constমোড়কে চিহ্নিত করা হয়নি । আমি আধুনিক বিধিগুলি অনুসরণ করে অনুমান করি: https://herbsutter.com/2013/01/01/video-you-dont-know-const-and-mutable/
এটি duplicateঅনুলিপি ব্যতীত অন্য কোনও অনুলিপি নির্ধারণকারীকে কার্যকর করার ভাল উপায় বলে মনে হচ্ছে const। সুতরাং আমি সরাসরি এটি করতে পারি না:
class A{
L* impl_; // the legacy object has to be in the heap
A(A const& other) : L{other.duplicate()}{} // error calling a non-const function
L* duplicate(){L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
তাহলে এই বিপরীতমুখী পরিস্থিতিটি কীভাবে বেরিয়ে আসার উপায়?
(আসুন এটিও legacy_duplicateথ্রেড-সেফ নয় তবে আমি জানি যে অবজেক্টটি যখন প্রস্থান করে তখন মূল অবস্থায় ফেলে দেয় a সি-ফাংশন হওয়ায় আচরণটি কেবল নথিভুক্ত থাকে তবে দৃ const়তার কোনও ধারণা নেই))
আমি অনেকগুলি সম্ভাব্য পরিস্থিতি সম্পর্কে ভাবতে পারি:
(1) একটি সম্ভাবনা হ'ল স্বাভাবিক শব্দার্থবিজ্ঞানের সাথে কোনও অনুলিপি নির্মাণকারীকে কার্যকর করার কোনও উপায় নেই। (হ্যাঁ, আমি বস্তুটি সরিয়ে ফেলতে পারি এবং এটি আমার প্রয়োজন হয় না))
(২) অন্যদিকে, কোনও বস্তুর অনুলিপি সহজাতভাবে অ-থ্রেড-নিরাপদ এই অর্থে যে একটি সাধারণ প্রকার অনুলিপি করার ফলে উত্সটি অর্ধ-সংশোধিত অবস্থায় খুঁজে পেতে পারে, তাই আমি কেবল এগিয়ে যেতে পারি এবং সম্ভবত এটি করতে পারি,
class A{
L* impl_;
A(A const& other) : L{const_cast<A&>(other).duplicate()}{} // error calling a non-const function
L* duplicate(){L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
(3) বা এমনকি duplicateকনস্ট্রাকটি ঘোষণা করুন এবং সমস্ত প্রসঙ্গে থ্রেড সুরক্ষা সম্পর্কে মিথ্যা বলুন। (সমস্ত উত্তরাধিকারের ফাংশনটির পরেও কোনও চিন্তা নেই constতাই সংকলক এমনকি অভিযোগও করবে না))
class A{
L* impl_;
A(A const& other) : L{other.duplicate()}{}
L* duplicate() const{L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
(4) অবশেষে, আমি যুক্তিটি অনুসরণ করতে পারি এবং একটি অনুলিপি যুক্তি গ্রহণকারী একটি অনুলিপি তৈরি করতে পারি ।
class A{
L* impl_;
A(A const&) = delete;
A(A& other) : L{other.duplicate()}{}
L* duplicate(){L* ret; legacy_duplicate(impl_, &ret); return ret;}
};
দেখা যাচ্ছে যে এটি অনেকগুলি প্রসঙ্গে কাজ করে, কারণ এই জিনিসগুলি সাধারণত হয় না const।
প্রশ্নটি হচ্ছে, এটি কি বৈধ বা সাধারণ রুট?
আমি তাদের নাম রাখতে পারি না, তবে আমি অজ্ঞাতসারে কন্ট্রাক্টর নন কনস্ট্রাক্টর থাকার কারণে প্রচুর সমস্যা আশা করি। সম্ভবত এই সূক্ষ্মতার কারণে এটি কোনও মান-ধরণের হিসাবে যোগ্যতা অর্জন করবে না।
(5) অবশেষে, যদিও এটি একটি ওভারকিল বলে মনে হচ্ছে এবং খাড়া রানটাইম ব্যয় হতে পারে, আমি একটি মিটেক্স যুক্ত করতে পারি:
class A{
L* impl_;
A(A const& other) : L{other.duplicate_locked()}{}
L* duplicate(){
L* ret; legacy_duplicate(impl_, &ret); return ret;
}
L* duplicate_locked() const{
std::lock_guard<std::mutex> lk(mut);
L* ret; legacy_duplicate(impl_, &ret); return ret;
}
mutable std::mutex mut;
};
তবে এটি করতে বাধ্য হওয়া হতাশার মতো দেখায় এবং শ্রেণিটিকে আরও বড় করে তোলে। আমি নিশ্চিত না. আমি বর্তমানে (4) , বা (5) বা উভয়ের সংমিশ্রনের দিকে ঝুঁকছি।
সম্পাদনা 1:
অন্য বিকল্প:
()) সদৃশ সদস্য ফাংশনের সমস্ত অজ্ঞানতা সম্পর্কে ভুলে যান এবং কেবল legacy_duplicateকনস্ট্রাক্টরের কাছ থেকে কল করুন এবং ঘোষণা করুন যে অনুলিপিটি নির্মাণকারী নিরাপদ নয়। (এবং প্রয়োজনে আরও একটি থ্রেড-সেফটি ভার্চুয়ান তৈরি করুন, A_mt)
class A{
L* impl_;
A(A const& other){legacy_duplicate(other.impl_, &impl_);}
};
সম্পাদনা 2:
উত্তরাধিকার ফাংশনটি যা করে তার জন্য এটি একটি ভাল মডেল হতে পারে। নোট করুন যে ইনপুটটি স্পর্শ করে কলটি প্রথম যুক্তি দ্বারা উপস্থাপিত মানের সাথে সুরক্ষিত নয়।
void legacy_duplicate(L* in, L** out){
*out = new L{};
char tmp = in[0];
in[0] = tmp;
std::memcpy(*out, in, sizeof *in); return;
}
সম্পাদনা 3:
আমি ইদানীং শিখেছি std::auto_ptrনন-কনস্ট্যান্ট "অনুলিপি" নির্মাণকারী একইরকম সমস্যা ছিল। প্রভাবটি auto_ptrএকটি ধারকটির ভিতরে ব্যবহার করা যায়নি। https://www.quantstart.com/articles/STL-Containers-and-Auto_ptrs-Why-They-Dont-Mix/
legacy_duplicateদুটি পৃথক থ্রেড থেকে একই প্রথম যুক্তি দিয়ে ফাংশনটি কল করা যায় না।
constসত্যিকারের অর্থ জানে না । :-) আমি const&যতক্ষণ না সংশোধন করি ততক্ষণ আমার কপি কর্টারে নিয়ে যাওয়া নিয়ে দু'বার চিন্তা করব না other। আমি সর্বদা থ্রেড সুরক্ষার কথা ভাবি কারণ একাধিক থ্রেড থেকে এনক্যাপসুলেশনের মাধ্যমে অ্যাক্সেস করা দরকার তার উপরে কিছু যুক্ত করে এবং আমি উত্তরগুলির অপেক্ষায় আছি।
Lযার মধ্যে একটি নতুনLউদাহরণ তৈরি করে সংশোধন করা হয়েছে ? যদি তা না হয় তবে কেন আপনি বিশ্বাস করেন যে এই অপারেশনটি থ্রেড-নিরাপদ নয়?