برنامه نویسی

سوالات مصاحبه C++ – انجمن DEV

Summarize this content to 400 words in Persian Lang

مقدمه

این یک مقاله بعدی برای سؤالات مصاحبه C است، بنابراین اگر آن را نخوانده اید، باید آن را مطالعه کنید. همانطور که در آنجا گفته شد، تمام آن سوالات C نیز سوالات معتبر C++ هستند، بنابراین می توان از داوطلبی که برای یک شغل C++ مصاحبه می کند، پرسید. البته C++ یک زبان بسیار بزرگتر از C است، بنابراین چندین سوال اضافی وجود دارد که مختص C++ هستند.

در اینجا چند سوال (همراه با پاسخ) وجود دارد که از یک نامزد در طول مصاحبه برای برنامه نویسی شغلی در C++ (علاوه بر سوالات C) می پرسم.

مانند قبل، اگر مبتدی هستید، توصیه می کنم قبل از کلیک کردن بر روی آن، سعی کنید به سوالات خود پاسخ دهید پاسخ دهید پیوندها

سوالات

سوال 1: متغیرهای محلی

با توجه به این تابع (where T یک نوع دلخواه است که در اینجا مهم نیست):

T& f() {
T t;
// …
return t;
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال: این تابع چه مشکلی دارد؟

این سوال اساساً همان سوال مصاحبه شماره 4 C است به جز اینکه منابع جایگزین نشانگرها می شوند.

پاسخ دهید
چون t یک متغیر محلی است، پس از بازگشت وجود خود را از دست خواهد داد، بنابراین مرجع a خواهد بود مرجع آویزان. تلاش برای دسترسی به مقدار ارجاع شده منجر به رفتار نامشخص می شود (و اگر خوش شانس باشید احتمالاً منجر به تخلیه اصلی می شود).

سوال 2: delete

چی دو وقتی تماس می گیرید اتفاقاتی می افتد delete?

پاسخ دهید

ویرانگر شی، در صورت وجود، فراخوانی می شود.
حافظه ای که شی مورد استفاده قرار می دهد اختصاص داده می شود.

سوال 3: delete[]

چه فرقی با هم دارند delete و delete[]?

پاسخ دهید
دشت delete برای از بین بردن یک شی منفرد استفاده می شود. delete[] برای از بین بردن مجموعه ای از اشیاء استفاده می شود.

سوال 4: اپراتورهای واگذاری

با توجه به دو کلاس ++C:

struct T {
T( T const& );
~T();
};

struct S {
T *p; // may be null

S& operator=( S const &that ) {
// …
}

~S() { delete p; }
};

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال 4 الف: عملگر انتساب کلاس را پیاده سازی کنید S به گونه ای که الف را اجرا می کند کپی عمیق، یعنی:

S x, y;
// …
x = y; // x.p points to a copy of *y.p, if any

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یادداشت ها:

این p عضو یک است دارای اشاره گر، یعنی S مسئول است به صورت پویا تخصیص، اشاره کرد T.
شما می توانید فقط از آن توابعی که به صراحت در اینجا اعلام شده است استفاده کنید.
جزئیات کلاس T مهم نیست فرض کنید که T(T const&) کپی های الف T به طور متعارف اعتراض کنید.

پاسخ دهید
یک پیاده سازی اولیه ممکن است:
S& S::operator=( S const &that ) {
if ( &that != this ) { // 2
delete p; // 3
p = that.p ? new T( *that.p ) : nullptr; // 4
}
return *this; // 6
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خط 2 از خود واگذاری محافظت می کند، یعنی:

x = x; // silly, but it still has to be correct

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خط 3 موجود را حذف می کند T، در صورت وجود

هست هرگز لازم است قبل از حذف یک اشاره گر از نظر null بررسی شود. C++ تضمین می کند که حذف یک اشاره گر تهی هیچ کاری نمی کند.

خط 4 آن را بررسی می کند that.p غیر پوچ است (همانطور که داده شد، p ممکن است null باشد) و به صورت پویا یک کپی از آن را اختصاص می دهد *p اگر نه در غیر این صورت، فقط مجموعه p باطل شدن

خط 5 برمی گردد *this همانطور که تمام اپراتورهای انتساب انجام می دهند.

سوال 4 ب ( ارشد): آیا اجرای استثنایی ایمن است؟ اگر نه، چگونه آن را ایمن می‌کنید؟

پاسخ دهید
پاسخ قبلی این است نه استثنا-ایمن زیرا اگر T(T const&) یک استثنا می اندازد T به که p امتیازها قبلاً حذف شده اند.

برای ایمن بودن در برابر استثنا، یک تابع باید طوری رفتار کند که گویی هیچ اتفاقی نیفتاده است. در این حالت اپراتور تخصیص باید نه را حذف کنید T به که p امتیاز

برای ایمن کردن آن در برابر استثنا، یک متغیر موقت معرفی کنید:

S& S::operator=( S const &that ) {
if ( &that != this ) {
T *t = that.p ? new T( *that.p ) : nullptr;
delete p; // 4
p = t;
}
return *this;
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا به جای حذف p ابتدا تماس بگیرید T(T const&) اول اگر یک استثنا ایجاد کند، خط 4 هرگز به آن نمی رسد. اگر کد به خط 4 رسید، به این معنی است که رسیده است نه یک استثنا پرتاب کنید اکنون حذف آن بی خطر است p.

سوال 4c ( ارشد): چی دو اگر این کار را انجام دهیم عواقب بدی در پی خواهد داشت نه اجرا کنند S::operator=(S const&)?

پاسخ دهید
بدون اجرای عملگر انتساب خودمان، کامپایلر به طور خودکار یک پیش فرض را ترکیب می کند که این کار را انجام می دهد. کپی کم عمق، که به سادگی مقدار the را کپی کنید p و نه را T به که p امتیاز این دو پیامد بد دارد:

سمت چپ T بلافاصله حافظه لو خواهد رفت.
سمت چپ و راست دست p به اشاره خواهد کرد همان T. وقتی اولین S نابود می شود، حذف می شود T. وقتی دومی S نابود می شود، سعی می کند آن را حذف کند T که دارد در حال حاضر حذف شده است. این به احتمال زیاد منجر به تخلیه هسته ای می شود.

سوال 5: std::map در مقابل std::unordered_map

چه تفاوت هایی وجود دارد std::map و std::unordered_map از نظر نحوه اجرای آنها معمولاً، زمان اجرا (نماد “O” بزرگ)، و زمانی که از یکی در مقابل دیگری استفاده می کنید؟

پاسخ دهید
std::map معمولاً با استفاده از یک درخت باینری متعادل اجرا می شود، به عنوان مثال، یک درخت قرمز-مشکی، که هم میانگین و هم بدترین زمان درج، جستجو و حذف برای آن همه است. O (log n).

std::unordered_map با استفاده از جدول هش اجرا می شود که میانگین زمان درج، جستجو و حذف برای آن همه است. O (1)، اما بدترین زمان ها همه آنها هستند O(n).

تکرار بیش از a map آیتم ها را به ترتیب مرتب شده برمی گرداند در حالی که تکرار بر روی یک unordered_map (همانطور که از نامش پیداست) ندارد.

به طور کلی، unordered_map به دلیل ترجیح داده می شود O(1) میانگین زمان عملکرد با این حال، اگر نیاز به تکرار به ترتیب مرتب شده دارید، باید از آن استفاده کنید map – اما این مستلزم این است که موارد وجود داشته باشند کمتر از قابل مقایسه.

سوال 6: virtual توابع

توابع مجازی معمولاً توسط کامپایلرهای C++ چگونه پیاده سازی می شوند؟

پاسخ دهید
هر کلاسی که حداقل یک تابع مجازی دارد، یک تابع مرتبط دارد vtbl (“جدول vee”) با یک “اسلات” برای هر تابع مجازی (از جمله تخریب کننده).

هر شکاف حاوی یک اشاره گر به تابع از اجرای لغو شده آن کلاس از تابع است. (اگر یک کلاس خاص تابع مجازی کلاس پایه خود را باطل نکند، در آن صورت شکاف آن حاوی یک اشاره گر به تابع پایه است.)

سپس هر شی از چنین کلاسی حاوی a است vptr (“اشاره گر vee”) که به vtbl برای کلاسش مقدار این اشاره گر نوع شی را در زمان اجرا تعیین می کند.

سوال 7: خطا را تشخیص دهید

داده شده:

struct S {
// Hint: the error is in the next line.
S() : p1{ new T }, p2{ new T } {
}

~S() {
delete p1;
delete p2;
}

T *p1, *p2;
};

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال 7a ( ارشد): اون کلاس چه مشکلی داره؟

پاسخ دهید
اگر T::T() در طول ساخت یک استثنا می اندازد p2، p1 نشت خواهد کرد زیرا تخریب کننده ها هستند نه فراخوانی شده برای اشیاء نیمه ساخته شده (در این مورد S، از این رو ~S() خواهد شد نه اجرا و delete p1 هرگز نامیده نخواهد شد).

سوال 7 ب ( ارشد): چطوری درستش میکنی؟

پاسخ دهید
شاید ساده ترین راه برای رفع این مشکل استفاده از آن باشد std::unique_ptr:
struct S {
S() : p1{ new T }, p2{ new T } {
}

std::unique_ptrT> p1, p2;
};

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حتی اگر تخریب کننده بر روی اشیایی که سازنده (یا سازنده یک عضو داده) آنها را پرتاب می کند، فراخوانی نمی شود، تخریب کننده ها هستند اعضای داده کاملاً ساخته شده را فراخواند.

در این مورد، p1ویرانگر نامیده می شود (در نتیجه آزاد می شود p1) اگر p2سازنده پرتاب می کند.

سوال 8: new

داده شده:

T *t = new( p ) T;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال 8a ( ارشد): این نحو به چه معناست؟

پاسخ دهید
به عنوان شناخته شده است قرار دادن جدید و برای ایجاد یک شی در یک آدرس حافظه خاص استفاده می شود، در این مورد، حافظه اشاره شده توسط p.

سوال 8 ب ( ارشد): در صورت وجود چه محدودیت(هایی) دارد؟

پاسخ دهید
آدرس باید متناسب با نوع شی در حال ساخت و اندازه کافی تراز باشد.

سوال 8c ( ارشد): چگونه چنین شیئی را از بین می برید؟

پاسخ دهید
شما باید صراحتاً ویرانگر آن را مانند:
t->~T();

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه گیری

اینها برخی از سوالات مصاحبه C++ مناسب هستند. هنگام مصاحبه با نامزدها به راحتی از آنها استفاده کنید.

مقدمه

این یک مقاله بعدی برای سؤالات مصاحبه C است، بنابراین اگر آن را نخوانده اید، باید آن را مطالعه کنید. همانطور که در آنجا گفته شد، تمام آن سوالات C نیز سوالات معتبر C++ هستند، بنابراین می توان از داوطلبی که برای یک شغل C++ مصاحبه می کند، پرسید. البته C++ یک زبان بسیار بزرگتر از C است، بنابراین چندین سوال اضافی وجود دارد که مختص C++ هستند.

در اینجا چند سوال (همراه با پاسخ) وجود دارد که از یک نامزد در طول مصاحبه برای برنامه نویسی شغلی در C++ (علاوه بر سوالات C) می پرسم.

مانند قبل، اگر مبتدی هستید، توصیه می کنم قبل از کلیک کردن بر روی آن، سعی کنید به سوالات خود پاسخ دهید پاسخ دهید پیوندها

سوالات


سوال 1: متغیرهای محلی

با توجه به این تابع (where T یک نوع دلخواه است که در اینجا مهم نیست):

T& f() {
  T t;
  // ...
  return t;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال: این تابع چه مشکلی دارد؟

این سوال اساساً همان سوال مصاحبه شماره 4 C است به جز اینکه منابع جایگزین نشانگرها می شوند.

پاسخ دهید

چون t یک متغیر محلی است، پس از بازگشت وجود خود را از دست خواهد داد، بنابراین مرجع a خواهد بود مرجع آویزان. تلاش برای دسترسی به مقدار ارجاع شده منجر به رفتار نامشخص می شود (و اگر خوش شانس باشید احتمالاً منجر به تخلیه اصلی می شود).


سوال 2: delete

چی دو وقتی تماس می گیرید اتفاقاتی می افتد delete?

پاسخ دهید
  1. ویرانگر شی، در صورت وجود، فراخوانی می شود.
  2. حافظه ای که شی مورد استفاده قرار می دهد اختصاص داده می شود.

سوال 3: delete[]

چه فرقی با هم دارند delete و delete[]?

پاسخ دهید

دشت delete برای از بین بردن یک شی منفرد استفاده می شود. delete[] برای از بین بردن مجموعه ای از اشیاء استفاده می شود.


سوال 4: اپراتورهای واگذاری

با توجه به دو کلاس ++C:

struct T {
  T( T const& );
  ~T();
};

struct S {
  T *p;     // may be null

  S& operator=( S const &that ) {
    // ...
  }

  ~S() { delete p; }
};
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال 4 الف: عملگر انتساب کلاس را پیاده سازی کنید S به گونه ای که الف را اجرا می کند کپی عمیق، یعنی:

S x, y;
// ...
x = y;      // x.p points to a copy of *y.p, if any
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یادداشت ها:

  • این p عضو یک است دارای اشاره گر، یعنی S مسئول است به صورت پویا تخصیص، اشاره کرد T.
  • شما می توانید فقط از آن توابعی که به صراحت در اینجا اعلام شده است استفاده کنید.
  • جزئیات کلاس T مهم نیست فرض کنید که T(T const&) کپی های الف T به طور متعارف اعتراض کنید.
پاسخ دهید

یک پیاده سازی اولیه ممکن است:

S& S::operator=( S const &that ) {
  if ( &that != this ) {                      // 2
    delete p;                                 // 3
    p = that.p ? new T( *that.p ) : nullptr;  // 4
  }
  return *this;                               // 6
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خط 2 از خود واگذاری محافظت می کند، یعنی:

x = x;      // silly, but it still has to be correct
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خط 3 موجود را حذف می کند T، در صورت وجود

هست هرگز لازم است قبل از حذف یک اشاره گر از نظر null بررسی شود. C++ تضمین می کند که حذف یک اشاره گر تهی هیچ کاری نمی کند.

خط 4 آن را بررسی می کند that.p غیر پوچ است (همانطور که داده شد، p ممکن است null باشد) و به صورت پویا یک کپی از آن را اختصاص می دهد *p اگر نه در غیر این صورت، فقط مجموعه p باطل شدن

خط 5 برمی گردد *this همانطور که تمام اپراتورهای انتساب انجام می دهند.

سوال 4 ب ( ارشد): آیا اجرای استثنایی ایمن است؟ اگر نه، چگونه آن را ایمن می‌کنید؟

پاسخ دهید

پاسخ قبلی این است نه استثنا-ایمن زیرا اگر T(T const&) یک استثنا می اندازد T به که p امتیازها قبلاً حذف شده اند.

برای ایمن بودن در برابر استثنا، یک تابع باید طوری رفتار کند که گویی هیچ اتفاقی نیفتاده است. در این حالت اپراتور تخصیص باید نه را حذف کنید T به که p امتیاز

برای ایمن کردن آن در برابر استثنا، یک متغیر موقت معرفی کنید:

S& S::operator=( S const &that ) {
  if ( &that != this ) {
    T *t = that.p ? new T( *that.p ) : nullptr;
    delete p;                                 // 4
    p = t;
  }
  return *this;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا به جای حذف p ابتدا تماس بگیرید T(T const&) اول اگر یک استثنا ایجاد کند، خط 4 هرگز به آن نمی رسد. اگر کد به خط 4 رسید، به این معنی است که رسیده است نه یک استثنا پرتاب کنید اکنون حذف آن بی خطر است p.

سوال 4c ( ارشد): چی دو اگر این کار را انجام دهیم عواقب بدی در پی خواهد داشت نه اجرا کنند S::operator=(S const&)?

پاسخ دهید

بدون اجرای عملگر انتساب خودمان، کامپایلر به طور خودکار یک پیش فرض را ترکیب می کند که این کار را انجام می دهد. کپی کم عمق، که به سادگی مقدار the را کپی کنید p و نه را T به که p امتیاز این دو پیامد بد دارد:

  1. سمت چپ T بلافاصله حافظه لو خواهد رفت.
  2. سمت چپ و راست دست p به اشاره خواهد کرد همان T. وقتی اولین S نابود می شود، حذف می شود T. وقتی دومی S نابود می شود، سعی می کند آن را حذف کند T که دارد در حال حاضر حذف شده است. این به احتمال زیاد منجر به تخلیه هسته ای می شود.

سوال 5: std::map در مقابل std::unordered_map

چه تفاوت هایی وجود دارد std::map و std::unordered_map از نظر نحوه اجرای آنها معمولاً، زمان اجرا (نماد “O” بزرگ)، و زمانی که از یکی در مقابل دیگری استفاده می کنید؟

پاسخ دهید

std::map معمولاً با استفاده از یک درخت باینری متعادل اجرا می شود، به عنوان مثال، یک درخت قرمز-مشکی، که هم میانگین و هم بدترین زمان درج، جستجو و حذف برای آن همه است. O (log n).

std::unordered_map با استفاده از جدول هش اجرا می شود که میانگین زمان درج، جستجو و حذف برای آن همه است. O (1)، اما بدترین زمان ها همه آنها هستند O(n).

تکرار بیش از a map آیتم ها را به ترتیب مرتب شده برمی گرداند در حالی که تکرار بر روی یک unordered_map (همانطور که از نامش پیداست) ندارد.

به طور کلی، unordered_map به دلیل ترجیح داده می شود O(1) میانگین زمان عملکرد با این حال، اگر نیاز به تکرار به ترتیب مرتب شده دارید، باید از آن استفاده کنید map – اما این مستلزم این است که موارد وجود داشته باشند کمتر از قابل مقایسه.

سوال 6: virtual توابع

توابع مجازی معمولاً توسط کامپایلرهای C++ چگونه پیاده سازی می شوند؟

پاسخ دهید

هر کلاسی که حداقل یک تابع مجازی دارد، یک تابع مرتبط دارد vtbl (“جدول vee”) با یک “اسلات” برای هر تابع مجازی (از جمله تخریب کننده).

هر شکاف حاوی یک اشاره گر به تابع از اجرای لغو شده آن کلاس از تابع است. (اگر یک کلاس خاص تابع مجازی کلاس پایه خود را باطل نکند، در آن صورت شکاف آن حاوی یک اشاره گر به تابع پایه است.)

سپس هر شی از چنین کلاسی حاوی a است vptr (“اشاره گر vee”) که به vtbl برای کلاسش مقدار این اشاره گر نوع شی را در زمان اجرا تعیین می کند.


سوال 7: خطا را تشخیص دهید

داده شده:

struct S {
  // Hint: the error is in the next line.
  S() : p1{ new T }, p2{ new T } {
  }

  ~S() {
    delete p1;
    delete p2;
  }

  T *p1, *p2;
};
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال 7a ( ارشد): اون کلاس چه مشکلی داره؟

پاسخ دهید

اگر T::T() در طول ساخت یک استثنا می اندازد p2، p1 نشت خواهد کرد زیرا تخریب کننده ها هستند نه فراخوانی شده برای اشیاء نیمه ساخته شده (در این مورد S، از این رو ~S() خواهد شد نه اجرا و delete p1 هرگز نامیده نخواهد شد).

سوال 7 ب ( ارشد): چطوری درستش میکنی؟

پاسخ دهید

شاید ساده ترین راه برای رفع این مشکل استفاده از آن باشد std::unique_ptr:

struct S {
  S() : p1{ new T }, p2{ new T } {
  }

  std::unique_ptrT> p1, p2;
};
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حتی اگر تخریب کننده بر روی اشیایی که سازنده (یا سازنده یک عضو داده) آنها را پرتاب می کند، فراخوانی نمی شود، تخریب کننده ها هستند اعضای داده کاملاً ساخته شده را فراخواند.

در این مورد، p1ویرانگر نامیده می شود (در نتیجه آزاد می شود p1) اگر p2سازنده پرتاب می کند.


سوال 8: new

داده شده:

T *t = new( p ) T;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سوال 8a ( ارشد): این نحو به چه معناست؟

پاسخ دهید

به عنوان شناخته شده است قرار دادن جدید و برای ایجاد یک شی در یک آدرس حافظه خاص استفاده می شود، در این مورد، حافظه اشاره شده توسط p.

سوال 8 ب ( ارشد): در صورت وجود چه محدودیت(هایی) دارد؟

پاسخ دهید

آدرس باید متناسب با نوع شی در حال ساخت و اندازه کافی تراز باشد.

سوال 8c ( ارشد): چگونه چنین شیئی را از بین می برید؟

پاسخ دهید

شما باید صراحتاً ویرانگر آن را مانند:

t->~T();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید


نتیجه گیری

اینها برخی از سوالات مصاحبه C++ مناسب هستند. هنگام مصاحبه با نامزدها به راحتی از آنها استفاده کنید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا