پست شماره ۱ move چیست , چرا به move نیاز داریم
چرا به move sematnic نیاز داریم ؟
شما فرض کنید یک کلاس دارین مثل vector که یک بلاک حافظه برای شما می گیره :
typedef std::vector<T> TVec;
TVec createTVec(); // factory function
TVec vt;
…
vt = createTVec(); // copy return value object to vt,
// then destroy return value object
الان داخل کد بالا خط 5 ام این اتفاقات میفته :
1_ createTVec صدا زده میشه و یک شی از TVec ساخته میشه
2_ operator= صدا زده میشه و مقادیر بازگشتی از createTVec کپی میشن در vt (یعنی ما در یک لحظه 2 تا کپی از وکتور داریم)
3_ نهایتا وکتور ساخته شده در مرحله اول پاک میشه
یعنی در یک زمان مشخص ما 2 تا کپی از اطلاعات داریم که این کپی شدن نه از نظر مصرف حافظه بهینست نه از نظر زمان مصرفی .
به نظرتون بهتر نبود که به جای کپی شدن فقط محلی که vt بهش اشاره می کنه رو عوض کنیم ؟ ( که اصطلاحا به این کار میگیم move )
حالا اگر به هر روشی بتونیم این کار رو انجام بدیم هم سرعت اجرای برنامه بیشتر میشد هم مصرف حافظه .
خب حالا یک مثال دیگه رو در نظر می گیریم :
فرض کنیم یک وکتور دیگه داریم به این شکل که
شامل یک سری عضو هست که هر کدوم به یک محل دیگه از حافظه اشاره می کنن (T State)
بعد وقتی که از push_back استفاده کنیم چه اتفاقی میفته ؟
یک بلاک بزرگتر حافظه گرفته میشه و تک تک عناصر کپی میشن باز هم این جا ما 2 تا کپی داریم
std::vector<T> vt;
...
vt.push_back(T object);
حالا بهتر نبود که عملیات این جوری انجام میشد ؟
یعنی فقط محلی که اشاره گر ها بهش اشاره می کنن رو عوض کنیم .
چیزایی که گفتم برای بقیه عملیات ها مثل insert erase و ... هم برقراره . به همین دلیله که listوvector و....توی c++11 سرعتشون از قبل بهتر شده .
یک مثال دیگه رو هم در نظر می گیریم برای swap کردن 2 تا مقدار :
template<typename T> // straightforward std::swap impl.
void swap(T& a, T& b)
{
T tmp(a); // copy a to tmp (⇒ 2 copies of a)
a = b; // copy b to a (⇒ 2 copies of b)
b = tmp; // copy tmp to b (⇒ 2 copies of tmp)
} // destroy tmp
این جا چه اتفاقی میفته ؟
مرجله اول یک کپی از a گرفته میشه و داخل b گذاشته میشه یعنی 2 تا کپی از a داریم
مرحله دوم یک کپی از b گرفته میشه و داخل a میزاریم یعنی 2 تا کپی از b داریم .
مرحله آخر هم یک کپی از temp گرفته میشه و توی b میزاریم یعنی 2 تا کپی از temp داریم !
حالا بهتر نبود تمام این کپی های غیر ضروری رو انجام ندیم و به این شکل عمل کنیم ؟
اطلاعات داخل a رو move کنیم به temp
اطلاعات داخل b رو move کنیم به a
اطلاعات داخل temp رو move کنیم به b
یعنی به جای کپی کردن فقط محلی که اشاره گر ها بهش اشاره می کنن رو عوض کنیم ؟
توی c++11 این کار شدنیه :
template<typename T> // straightforward std::swap impl.
void swap(T& a, T& b)
{
T tmp(std::move(a)); // move a’s data to tmp
a = std::move(b); // move b’s data to a
b = std::move(tmp); // move tmp’s data to b
}
چه زمانی استفاده از move بهتر از کپی کردنه ؟
1_ همون جوری که توی مثال های بالا بهش اشاره کردم زمانی move سریع تره که بتونیم اشاره گر ها رو عوض کنیم .(یهنی عناصر توی 2 قسمت جدا از حافظه قرار گرفته باشن )
یعنی فرضا اگر داخل مثال دومی که زدم T State هم داخل یک بلاک حافظه بود این جا کپی کردن یا move کردن فرقی نداشت .
2_ زمان های که قراره deep copyانجام بشه استفاده از move خیلی بهتر جواب میده .
نکته ای هم که هست اینه که move هیچ وقت از copy کند تر نیست و اغلب وقت ها هم سریع تره پس بهتره همیشه استفاده بشه .
نمودار زیر مقایسه move و copy برای = و push_back برای 10000 تا عنصره
vt = createTVec(); // return/assignment
vt.push_back(T object); // push_back
همون طوری که مشخصه move خیلی وقت ها به مراتب سریع تر از copy هستش .