برای آموزش QML هم Downloadly یه سری دوره از Udemy آپلود کرده با عناوین
Qt6 and Qml for begginers
Qt6 and Qml for Intermediate
Qt6 and Qml for Advanced
بنظرم خوب هستن
#cpp
#qt
#programming
Qt6 and Qml for begginers
Qt6 and Qml for Intermediate
Qt6 and Qml for Advanced
بنظرم خوب هستن
#cpp
#qt
#programming
❤2
همزمانی در سیپلاسپلاس
پست یک
خب سیپلاسپلاس و stl یه مجموعه کاملی برای concurrency دارن.
مهم ترینش شاید بشه گفت کلاس std::thread باشه که ریسورسای لازم یک ثرد رو از سیستم عامل میگیره. فرض کنین بخوایم یه تابع رو به شکل همزمان اجرا کنیم شکل کلی برنامه اینجوری میشه:
نکته های خیلی زیادی داره این چندخط که سعی میکنم چندتاشو بگم
۱) یه آبجکت ثرد به محض ساخته شدن، شروع به اجرا میکنه و با stl تاجایی که بنده میدونم نمیتونیم ثردی که از اول ساسپند شده بسازیم
۲) بعد از اینکه به آبجکت از std::thread میسازیم، یا باید joinاش رو صدا کنیم تا ثرد اصلی تا موقع تموم شدن کارش صبر کنه یا detach رو صدا کنیم تا ثرد بره توی پس زمینه اجراشه (کنترل ثرد بیوفته دست کتابخانه رانتایم cpp).
حالا سوال اینه اگه جوین یا دیتچ رو صدا نکنیم چه اتفاقی میوفته؟
اتفاقای بد
خیلی بد😂
۳) توی دیستراکتور thread، اگه یه ثرد جوین یا دیتچ نشده باشه، تابع std::terminate صدا زده میشه که کلا برنامه رو میبنده پس حتما باید قبل از ازبین رفتن آبجکت یکی از ایندوتا تابع رو صدا بزنیم. (یکی از جاهایی که مهمه حواسمون به این نکته باشه، وقتیه که بین ساختن آبجکت و جوین یا دیتچ کردنش یه کد داشته باشیم که exception تولید کنه اینجورجاها بهتره از std::jthread استفاده کنیم. توضیحش خارج از این پسته)
۴) یه ثرد وقتی join یا detachاش صدا زده میشه، تابع std::thread::joinable اش دیگه تا ابد false برمیگردونه. دلیلش سادست. اگه join رو صدا زده باشیم و بعدش joinable رو، قاعدتا تا ثرد تموم نشه، به joinable نمیرسیم و وقتی برسیم ثرد تموم شده و دیگه وجود نداره که بخوایم جوینش کنیم. اگه دیتچ کرده باشیم هم یه ثرد داریم که دیگه دست ما نیست کنترلش و کلا هیچ کنترلی روش نخواهیم داشت. پس باز هم منطقیه که joinable فالس برگردونه.
درواقع دیستراکتور std::thread هم از همین تابع استفاده میکنه تا چک کنه ببینه باید terminate کنه یا نه
۵) اگه تابعی که قراره به صورت همزمان اجرا بشه یه سری متغیر ورودی داشته باشه، توی std::thread این متغیرا رو پاس میدیم ولی باید حواسمون باشه که متغیرها کپی خواهند شد. حتی اگه رفرنس باشن🥸
این یه سری نکته داره که ایشالا بعدا میگم
ادامه
#programming
#cpp
#concurrency
پست یک
خب سیپلاسپلاس و stl یه مجموعه کاملی برای concurrency دارن.
مهم ترینش شاید بشه گفت کلاس std::thread باشه که ریسورسای لازم یک ثرد رو از سیستم عامل میگیره. فرض کنین بخوایم یه تابع رو به شکل همزمان اجرا کنیم شکل کلی برنامه اینجوری میشه:
#include <thread>
void someConcurrentFunction(){}
int main(){
auto th=std::thread(someFunction);
th.join(); //or th.detach()
}
نکته های خیلی زیادی داره این چندخط که سعی میکنم چندتاشو بگم
۱) یه آبجکت ثرد به محض ساخته شدن، شروع به اجرا میکنه و با stl تاجایی که بنده میدونم نمیتونیم ثردی که از اول ساسپند شده بسازیم
۲) بعد از اینکه به آبجکت از std::thread میسازیم، یا باید joinاش رو صدا کنیم تا ثرد اصلی تا موقع تموم شدن کارش صبر کنه یا detach رو صدا کنیم تا ثرد بره توی پس زمینه اجراشه (کنترل ثرد بیوفته دست کتابخانه رانتایم cpp).
حالا سوال اینه اگه جوین یا دیتچ رو صدا نکنیم چه اتفاقی میوفته؟
اتفاقای بد
خیلی بد😂
۳) توی دیستراکتور thread، اگه یه ثرد جوین یا دیتچ نشده باشه، تابع std::terminate صدا زده میشه که کلا برنامه رو میبنده پس حتما باید قبل از ازبین رفتن آبجکت یکی از ایندوتا تابع رو صدا بزنیم. (یکی از جاهایی که مهمه حواسمون به این نکته باشه، وقتیه که بین ساختن آبجکت و جوین یا دیتچ کردنش یه کد داشته باشیم که exception تولید کنه اینجورجاها بهتره از std::jthread استفاده کنیم. توضیحش خارج از این پسته)
۴) یه ثرد وقتی join یا detachاش صدا زده میشه، تابع std::thread::joinable اش دیگه تا ابد false برمیگردونه. دلیلش سادست. اگه join رو صدا زده باشیم و بعدش joinable رو، قاعدتا تا ثرد تموم نشه، به joinable نمیرسیم و وقتی برسیم ثرد تموم شده و دیگه وجود نداره که بخوایم جوینش کنیم. اگه دیتچ کرده باشیم هم یه ثرد داریم که دیگه دست ما نیست کنترلش و کلا هیچ کنترلی روش نخواهیم داشت. پس باز هم منطقیه که joinable فالس برگردونه.
درواقع دیستراکتور std::thread هم از همین تابع استفاده میکنه تا چک کنه ببینه باید terminate کنه یا نه
۵) اگه تابعی که قراره به صورت همزمان اجرا بشه یه سری متغیر ورودی داشته باشه، توی std::thread این متغیرا رو پاس میدیم ولی باید حواسمون باشه که متغیرها کپی خواهند شد. حتی اگه رفرنس باشن🥸
این یه سری نکته داره که ایشالا بعدا میگم
ادامه
#programming
#cpp
#concurrency
Stuff for Geeks
همزمانی در سیپلاسپلاس پست یک خب سیپلاسپلاس و stl یه مجموعه کاملی برای concurrency دارن. مهم ترینش شاید بشه گفت کلاس std::thread باشه که ریسورسای لازم یک ثرد رو از سیستم عامل میگیره. فرض کنین بخوایم یه تابع رو به شکل همزمان اجرا کنیم شکل کلی برنامه اینجوری…
همزمانی در سیپلاسپلاس
پست ۲
تو این پست میخوام در مورد مشکلی که آخر پست یک بهش اشاره شد، بگم. مشکلی که ما با پاس دادن متغیر به std::thread که یه کانستراکتور هست، داریم. فرض کنید که یه تابع مثل زیر داریم و میخوایم اون رو به std::thread پاس بدیم:
خب حالا فرض کنید یه ثرد با این تابع بسازیم:
این کد مشکل ساز خواهد بود
هرچند که اینجا کار میکنه، ولی در ادامه میبینیم که این کد مشکلات بزرگی داره
دلیلش اینه که متنی که داخل دابل کوت قرار داره، یه آبجکت استرینگ نیست و درحقیقت یه
درواقع someFunction یه استرینگ میگیره ولی متد std::thread یه سری ورودی میگیره که جنسشون ربطی به اینکه جنس پارامترهای someFunction چیه نداره. پس اینجا به مشکل میخوریم. مشکل وقتی جدی میشه که پارامتری که داریم به std::thread پاس میدیم، یه پوینتر اتوماتیک باشه که از اسکوپ خارج شده باشه ولی ثرد بهش نیاز داشته باشه. اینجاست که کدمون خطری میشه.
راه حل چیه؟
راه حل اینه که واضحا به کامپایلر بگیم که میخوایم استرینگ پاس بدیم. کد زیر، کد درسته:
همین قضیه برای رفرنس برقراره. البته ایندفعه کامپایلر ارور میده. مثلا کد زیر، خطای کامپایل خواهد داشت:
اینجا هم باید به کامپایلر واضح بگیم که باید رفرنس پاس بده. برای اینکار باید از std::ref استفاده کنیم که یه wrapper برای reference هست:
و کد کامپایل خواهد شد.
ادامه
#programming
#cpp
#concurrency
پست ۲
تو این پست میخوام در مورد مشکلی که آخر پست یک بهش اشاره شد، بگم. مشکلی که ما با پاس دادن متغیر به std::thread که یه کانستراکتور هست، داریم. فرض کنید که یه تابع مثل زیر داریم و میخوایم اون رو به std::thread پاس بدیم:
void someFunction(std::string someString){
//some processing
}خب حالا فرض کنید یه ثرد با این تابع بسازیم:
int main(){
std::thread th(someFunction, "some string");
th.join();
return 0;
}این کد مشکل ساز خواهد بود
هرچند که اینجا کار میکنه، ولی در ادامه میبینیم که این کد مشکلات بزرگی داره
دلیلش اینه که متنی که داخل دابل کوت قرار داره، یه آبجکت استرینگ نیست و درحقیقت یه
cons char* عه.درواقع someFunction یه استرینگ میگیره ولی متد std::thread یه سری ورودی میگیره که جنسشون ربطی به اینکه جنس پارامترهای someFunction چیه نداره. پس اینجا به مشکل میخوریم. مشکل وقتی جدی میشه که پارامتری که داریم به std::thread پاس میدیم، یه پوینتر اتوماتیک باشه که از اسکوپ خارج شده باشه ولی ثرد بهش نیاز داشته باشه. اینجاست که کدمون خطری میشه.
راه حل چیه؟
راه حل اینه که واضحا به کامپایلر بگیم که میخوایم استرینگ پاس بدیم. کد زیر، کد درسته:
int main(){
std::thread th(someFunction, std::string("some string"));
th.join();
return 0;
}همین قضیه برای رفرنس برقراره. البته ایندفعه کامپایلر ارور میده. مثلا کد زیر، خطای کامپایل خواهد داشت:
void foo(int& someRef){
//...
}
int main(){
int i=10;
std::thread th(foo, i);
th.join();
return 0;
}اینجا هم باید به کامپایلر واضح بگیم که باید رفرنس پاس بده. برای اینکار باید از std::ref استفاده کنیم که یه wrapper برای reference هست:
void foo(int& someRef){
//...
}
int main(){
int i=10;
std::thread th(foo, std::ref(i));
th.join();
return 0;
}و کد کامپایل خواهد شد.
ادامه
#programming
#cpp
#concurrency
Stuff for Geeks
همزمانی در سیپلاسپلاس پست ۲ تو این پست میخوام در مورد مشکلی که آخر پست یک بهش اشاره شد، بگم. مشکلی که ما با پاس دادن متغیر به std::thread که یه کانستراکتور هست، داریم. فرض کنید که یه تابع مثل زیر داریم و میخوایم اون رو به std::thread پاس بدیم: void som…
همزمانی در سیپلاسپلاس
پست ۳
تو این پست میخوام درمورد std::jthread که از C++17 به stl اضافه شده یه صبحتی بکنیم.
این کلاس یه خاصیت خوب داره:
توی دیستراکتورش، چک میکنه اگه ثرد جوین نشده بود جوینش میکنه.
چرا این خاصیت خوبه؟
چون ما معمولا یه ثرد که میسازیم، چندین خط بعد جوین یا دیتچش میکنم و به همین دلیل ممکنه بین ساختنش تا جوین شدنش اکسپشن رخ بده یا اتفاقای دیگه که باعث شده ثرد جوین نشه. و همونطور که قبلا گفتیم، اگه یه ثرد عادی (std::thread) جوین نشه و دیستراکتورش صدا زده بشه، برنامه کامل بسته میشه(std::terminate).
پس خوبه که بجای std::thread که توی C++11 اضافه شد، از std::jthread استفاده کنیم.
ادامه
#cpp
#programming
#comcurrency
پست ۳
تو این پست میخوام درمورد std::jthread که از C++17 به stl اضافه شده یه صبحتی بکنیم.
این کلاس یه خاصیت خوب داره:
توی دیستراکتورش، چک میکنه اگه ثرد جوین نشده بود جوینش میکنه.
چرا این خاصیت خوبه؟
چون ما معمولا یه ثرد که میسازیم، چندین خط بعد جوین یا دیتچش میکنم و به همین دلیل ممکنه بین ساختنش تا جوین شدنش اکسپشن رخ بده یا اتفاقای دیگه که باعث شده ثرد جوین نشه. و همونطور که قبلا گفتیم، اگه یه ثرد عادی (std::thread) جوین نشه و دیستراکتورش صدا زده بشه، برنامه کامل بسته میشه(std::terminate).
پس خوبه که بجای std::thread که توی C++11 اضافه شد، از std::jthread استفاده کنیم.
ادامه
#cpp
#programming
#comcurrency
Stuff for Geeks
همزمانی در سیپلاسپلاس پست ۳ تو این پست میخوام درمورد std::jthread که از C++17 به stl اضافه شده یه صبحتی بکنیم. این کلاس یه خاصیت خوب داره: توی دیستراکتورش، چک میکنه اگه ثرد جوین نشده بود جوینش میکنه. چرا این خاصیت خوبه؟ چون ما معمولا یه ثرد که میسازیم،…
همزمانی در سیپلاسپلاس
پست ۴
خب
حالا که چندین ثرد داریم، اگه خواسته باشیم یه حافظهای بین اینا به اشتراک بذاریم(shared_momry) باید چیکار کنیم؟
تعداد زیادی از مشکلات و مباحث همزمانی از اینجا شروع میشه.
مشکل اول، race condition:
یه مثال معروفی هست برای اینکه بفهمیم این مشکل چیه. فرض کنید رفتین سینما یا تئاتر و دهتا از مسئولین سالن دارن برای هر صندلی بلیت میفروشن. (صندلیها میشن shared memory و ماموران فروش میشن ثردها)
حالا اینجا مشکل اولی که پیش میاد اینه که اگه ماموران فروش خوب هماهنگ نشده باشن، ممکنه یه صندلی رو به دو یا چندتانفر بفروشن که قاعدتا کار اشتباهیه
اینجا هم همین مشکل هست
فرض کنید دوتا ثرد بخوان به عددی که تو یه خونه از حافظه هست رو بخونن(read) و مقدارش رو یک واحد اضافه کنن(write).
این مورد هم توجه داشته باشید که دیتا متاسفانه کش میشه. ینی از مموری اصلی(رم) خونده میشه و تا یه مدت کوتاهی توی سی پی یو هست.
حالا فرض کنید مقداری که توی حافظه هست عدد ده باشه.
ثرد یک این مقدار رو میخونه(۱۰) و این مقدار خونده شده میاد تو کش.
میاد یکی بهش اضافه کنه ولی تا بخواد اضافه کنه، ثرد دو چون همزمان داره اجرا میشه، ممکنه بیاد و بخواد عملیات خوندن رو انجام بده و چون توی کش مقدار ده رو داریم، عدد ده رو خواهد خوند. بعد هر ثرد یکی اضافه میکنن به این مقدار که میشه یازده و توی مموری مینویسنش.
انتظارمون این بود به عدد دوازده توی مموری برسیم(چون دوتا ثرد هرکدوم داشتن به یه متغیر یه واحد اضافه میکردن) ولی ممکنه به عدد یازده هم برسیم.
برای رفع این مشکل ساختارهای متفاوتی در سطح نرمافزاری و سخت افزاری داریم. در سطح نرمافزاری یا دقیق تر سیستم عاملی، mutex و semaphore و در سطح سختافزاری atomic operation ها رو داریم که در ادامه بررسی خواهند شد
ادامه
#programming
#cpp
#comcurrency
پست ۴
خب
حالا که چندین ثرد داریم، اگه خواسته باشیم یه حافظهای بین اینا به اشتراک بذاریم(shared_momry) باید چیکار کنیم؟
تعداد زیادی از مشکلات و مباحث همزمانی از اینجا شروع میشه.
مشکل اول، race condition:
یه مثال معروفی هست برای اینکه بفهمیم این مشکل چیه. فرض کنید رفتین سینما یا تئاتر و دهتا از مسئولین سالن دارن برای هر صندلی بلیت میفروشن. (صندلیها میشن shared memory و ماموران فروش میشن ثردها)
حالا اینجا مشکل اولی که پیش میاد اینه که اگه ماموران فروش خوب هماهنگ نشده باشن، ممکنه یه صندلی رو به دو یا چندتانفر بفروشن که قاعدتا کار اشتباهیه
اینجا هم همین مشکل هست
فرض کنید دوتا ثرد بخوان به عددی که تو یه خونه از حافظه هست رو بخونن(read) و مقدارش رو یک واحد اضافه کنن(write).
این مورد هم توجه داشته باشید که دیتا متاسفانه کش میشه. ینی از مموری اصلی(رم) خونده میشه و تا یه مدت کوتاهی توی سی پی یو هست.
حالا فرض کنید مقداری که توی حافظه هست عدد ده باشه.
ثرد یک این مقدار رو میخونه(۱۰) و این مقدار خونده شده میاد تو کش.
میاد یکی بهش اضافه کنه ولی تا بخواد اضافه کنه، ثرد دو چون همزمان داره اجرا میشه، ممکنه بیاد و بخواد عملیات خوندن رو انجام بده و چون توی کش مقدار ده رو داریم، عدد ده رو خواهد خوند. بعد هر ثرد یکی اضافه میکنن به این مقدار که میشه یازده و توی مموری مینویسنش.
انتظارمون این بود به عدد دوازده توی مموری برسیم(چون دوتا ثرد هرکدوم داشتن به یه متغیر یه واحد اضافه میکردن) ولی ممکنه به عدد یازده هم برسیم.
برای رفع این مشکل ساختارهای متفاوتی در سطح نرمافزاری و سخت افزاری داریم. در سطح نرمافزاری یا دقیق تر سیستم عاملی، mutex و semaphore و در سطح سختافزاری atomic operation ها رو داریم که در ادامه بررسی خواهند شد
ادامه
#programming
#cpp
#comcurrency
Stuff for Geeks
همزمانی در سیپلاسپلاس پست ۴ خب حالا که چندین ثرد داریم، اگه خواسته باشیم یه حافظهای بین اینا به اشتراک بذاریم(shared_momry) باید چیکار کنیم؟ تعداد زیادی از مشکلات و مباحث همزمانی از اینجا شروع میشه. مشکل اول، race condition: یه مثال معروفی هست برای اینکه…
همزمانی در سیپلاسپلاس
پست ۵
توی این پست میخوام درمورد mutex صحبت کنم. توی پست قبلی گفتیم که دسترسی چند ثرد به یه ریسورس، مشکلساز میشه و باید کنترل شه. یکی از ابزارهامون همین mutex هست. با mutex میتونیم قسمتهایی از کد که با یک shared memory کار دارن رو بهشون یه برچسب بزنیم و بگیم که این تیکه باید توسط یک ثرد کامل انجام بشه و تا انجام نشده ثرد دیگهای نباید مداخله کنه. اینجوری یه بخشی از مشکلات حل میشه. درواقع mutex مخفف mutual exclusive هست که همین قضیه رو نشون میده.
به اون تیکه از کد که برچسب زدیم بهش هم، critical section میگن.
استفاده از میوتکس توی سیپلاسپلاس راحته ولی باید طراحی همزمانی با وسواس و دقت زیادی انجام بشه چون صرف استفاده از میوتکس، دلیل بر رفع مشکل مخصوصا مشکلات طراحی نمیشه.
خب فرض کنید میخوایم یه تیکه از کد رو بگیم که mutual exclusive هست. اینجوری میشه:
البته چون لاک و آنلاک کردن دستی میوتکس یه آنتیپترن حساب میشه، یه سری کلاسهای دیگه مثل lock_gaurd داریم که یه میوتکس میگیره، لاک میکنه و با خارج شدن از اسکوپ، اون رو آنلاک میکنه.
یعنی کد بالا با lock_gaurd به شکل زیر تغییر میکنه:
و چندین کلاس دیگه هم داریم. مثلا scoped_lock که توی C++17 اضافه شده، نسخه بهتر lock_gaurd حساب میشه. این کلاس یک یا چندتا میوتکس میگیره و جوری لاک و آنلاکشون میکنه که dead lock پیش نیاد.
حالا dead lock چیه؟
اگه دوتا ریسورس r1 و r2 و میوتکسهای m1 و m2 رو داشته باشیم و دوتا ثرد t1 و t2 که به این ریسورسها نیاز دارن، اگه ترتیب لاک و آنلاک شدن بد باشه به ددلاک میخوریم.
مثلا t1 به r2 نیاز داره که توسط m2 و t2 لاک شده و شرط آنلاک شدنش دسترسی به r1 عه درحالیکه r1 توسط m1 و t1 لاک شده.
اینجاست که هیچ وقت ریسورسها آنلاک نمیشن و ثردها تا همیشه تو صف انتظار میمونن!
پس scoped_lock این مشکل رو حل میکنه ولی بازم تاکید میکنم که استفاده از میوتکس خوب و درسته درصورتیکه طراحی درست باشه
توی پست بعدی درمورد طراحی اشتباه و مشکلاتش صحبت میکنم
ادامه
#cpp
#concurrency
#programming
پست ۵
توی این پست میخوام درمورد mutex صحبت کنم. توی پست قبلی گفتیم که دسترسی چند ثرد به یه ریسورس، مشکلساز میشه و باید کنترل شه. یکی از ابزارهامون همین mutex هست. با mutex میتونیم قسمتهایی از کد که با یک shared memory کار دارن رو بهشون یه برچسب بزنیم و بگیم که این تیکه باید توسط یک ثرد کامل انجام بشه و تا انجام نشده ثرد دیگهای نباید مداخله کنه. اینجوری یه بخشی از مشکلات حل میشه. درواقع mutex مخفف mutual exclusive هست که همین قضیه رو نشون میده.
به اون تیکه از کد که برچسب زدیم بهش هم، critical section میگن.
استفاده از میوتکس توی سیپلاسپلاس راحته ولی باید طراحی همزمانی با وسواس و دقت زیادی انجام بشه چون صرف استفاده از میوتکس، دلیل بر رفع مشکل مخصوصا مشکلات طراحی نمیشه.
خب فرض کنید میخوایم یه تیکه از کد رو بگیم که mutual exclusive هست. اینجوری میشه:
#include <mutex>
using std::mutex;
int main(){
mutex m1;
...
//Start of critical section
m1.lock()
...
m1.unlock()
//End of critical section
}
البته چون لاک و آنلاک کردن دستی میوتکس یه آنتیپترن حساب میشه، یه سری کلاسهای دیگه مثل lock_gaurd داریم که یه میوتکس میگیره، لاک میکنه و با خارج شدن از اسکوپ، اون رو آنلاک میکنه.
یعنی کد بالا با lock_gaurd به شکل زیر تغییر میکنه:
//Start of critical section
{
lock_gaurd lock1{m1} //m1 is locked now
}
//End of critical section
//m1 gets unlocked in lock1 destructor (RAII)
و چندین کلاس دیگه هم داریم. مثلا scoped_lock که توی C++17 اضافه شده، نسخه بهتر lock_gaurd حساب میشه. این کلاس یک یا چندتا میوتکس میگیره و جوری لاک و آنلاکشون میکنه که dead lock پیش نیاد.
حالا dead lock چیه؟
اگه دوتا ریسورس r1 و r2 و میوتکسهای m1 و m2 رو داشته باشیم و دوتا ثرد t1 و t2 که به این ریسورسها نیاز دارن، اگه ترتیب لاک و آنلاک شدن بد باشه به ددلاک میخوریم.
مثلا t1 به r2 نیاز داره که توسط m2 و t2 لاک شده و شرط آنلاک شدنش دسترسی به r1 عه درحالیکه r1 توسط m1 و t1 لاک شده.
اینجاست که هیچ وقت ریسورسها آنلاک نمیشن و ثردها تا همیشه تو صف انتظار میمونن!
پس scoped_lock این مشکل رو حل میکنه ولی بازم تاکید میکنم که استفاده از میوتکس خوب و درسته درصورتیکه طراحی درست باشه
توی پست بعدی درمورد طراحی اشتباه و مشکلاتش صحبت میکنم
ادامه
#cpp
#concurrency
#programming
push_back(c++11)?
emplace_back(c++17)?
مسئله اینست
فرض کنید که یک کلاس با تعداد زیادی فیلد(سایز زیاد) داریم و میخوایم یه وکتور از این تایپ داشته باشیم:
خب حالا چجوری داخل یه وکتور اشیائی ازین کلاس رو وارد کنیم؟
آیا پوش بک بهینست؟
برای جواب به این سوال، فرض کنید یه شیئ ساخته شده از کلاس حجیممون داریم. مثلا اسمش b باشه. وکتورمون هم فرضا v باشه، وقتی مینویسیم:
v.push_back(b)
اتفاقی که معمولا میوفته اینه که b کپی میشه و داخل v پوش میشه.
این کپی کردنه مشکل ماجراست که باعث میشه ریسورس زیادی از دست بدیم پس چه کنیم؟
از تابع emplace_back استفاده میکنیم. این تابع، مزیتی که داره اینه که با گرفتن پارامترهای لازم برای ساختن یه شیئ از کلاس مدنظر، اون شیئ رو میسازه و move میکنه داخل وکتور.(اگه نمیدونین move چیه سرچ کنید move semantics)
خلاصه که اینجوری دیگه شیئ اضافی کپی نمیشه و خیالمون راحته.
البته میشه اینجوری هم کار رو درآورد:
v.push_back(std::move(b))
ولی بعد اینکار b از بین میره و دسترسی بهش باعث undefined behavior میشه.
خب پس اگه لازم بود شیئ بسازین و داخل وکتور قرار بدین، همیشه emplace_back بهتر از push_back خواهد بود.
#cpp
#programming
emplace_back(c++17)?
مسئله اینست
فرض کنید که یک کلاس با تعداد زیادی فیلد(سایز زیاد) داریم و میخوایم یه وکتور از این تایپ داشته باشیم:
class BigStructure{
//lots of fields
//...
};خب حالا چجوری داخل یه وکتور اشیائی ازین کلاس رو وارد کنیم؟
آیا پوش بک بهینست؟
برای جواب به این سوال، فرض کنید یه شیئ ساخته شده از کلاس حجیممون داریم. مثلا اسمش b باشه. وکتورمون هم فرضا v باشه، وقتی مینویسیم:
v.push_back(b)
اتفاقی که معمولا میوفته اینه که b کپی میشه و داخل v پوش میشه.
این کپی کردنه مشکل ماجراست که باعث میشه ریسورس زیادی از دست بدیم پس چه کنیم؟
از تابع emplace_back استفاده میکنیم. این تابع، مزیتی که داره اینه که با گرفتن پارامترهای لازم برای ساختن یه شیئ از کلاس مدنظر، اون شیئ رو میسازه و move میکنه داخل وکتور.(اگه نمیدونین move چیه سرچ کنید move semantics)
خلاصه که اینجوری دیگه شیئ اضافی کپی نمیشه و خیالمون راحته.
البته میشه اینجوری هم کار رو درآورد:
v.push_back(std::move(b))
ولی بعد اینکار b از بین میره و دسترسی بهش باعث undefined behavior میشه.
خب پس اگه لازم بود شیئ بسازین و داخل وکتور قرار بدین، همیشه emplace_back بهتر از push_back خواهد بود.
#cpp
#programming