في C ++ ، هناك عدد غير قليل من الميزات التي يمكن اعتبارها خطرة - مع الحسابات الخاطئة في التصميم أو الترميز غير الدقيق ، يمكن أن تؤدي بسهولة إلى الأخطاء. توفر المقالة مجموعة مختارة من هذه الميزات ، وتعطي نصائح حول كيفية تقليل تأثيرها السلبي.
جدول المحتويات
Praemonitus ، praemunitus.
تحذير مسبق يعني مسلح. (خط الطول).
مقدمة
في C ++ ، هناك عدد غير قليل من الميزات التي يمكن اعتبارها خطرة - مع الحسابات الخاطئة في التصميم أو الترميز غير الدقيق ، يمكن أن تؤدي بسهولة إلى الأخطاء. يمكن أن يُعزى بعضها إلى طفولة صعبة ، وبعضها إلى معيار C ++ 98 القديم ، ولكن البعض الآخر مرتبط بالفعل بميزات C ++ الحديثة. فكر في العوامل الرئيسية وحاول تقديم المشورة حول كيفية تقليل تأثيرها السلبي.
1. الأنواع
1.1. التعليمات والمشغلين الشرطيين
تؤدي الحاجة إلى التوافق مع C إلى حقيقة أنه في العبارة if(...)
وما شابه ، يمكنك استبدال أي تعبير رقمي أو مؤشر ، وليس مجرد تعبيرات مثل bool
. وتتفاقم المشكلة من خلال التحويل الضمني من bool
إلى int
في التعبيرات الحسابية وأولوية بعض عوامل التشغيل. وهذا يؤدي ، على سبيل المثال ، إلى الأخطاء التالية:
if(a=b)
عندما يكون صحيحًا if(a==b)
،
if(a<x<b)
، عندما يكون صحيحًا if(a<x && x<b)
،
if(a&x==0)
، عندما يكون صحيحًا if((a&x)==0)
،
if(Foo)
صحيحًا if(Foo())
،
if(arr)
عندما يكون صحيحًا if(arr[0])
،
if(strcmp(s,r))
عند تصحيحها if(strcmp(s,r)==0)
.
تتسبب بعض هذه الأخطاء في تحذير مترجم ، ولكن ليس خطأ. يمكن أن يساعد محللو الكود أحيانًا. في C # ، تكاد تكون هذه الأخطاء مستحيلة ، if(...)
وتعليمات مماثلة تتطلب نوعًا bool
، فلا يمكنك مزج الأنواع bool
في التعبيرات الحسابية.
كيفية القتال:
- برنامج بدون تحذيرات. لسوء الحظ ، هذا لا يساعد دائمًا ؛ بعض الأخطاء الموضحة أعلاه لا تعطي تحذيرات.
- استخدم محللات التعليمات البرمجية الثابتة.
- تقنية الاستقبال القديمة: عند المقارنة بثابت ، ضعها على اليسار ، على سبيل المثال
if(MAX_PATH==x)
. إنها تبدو جميلة جدًا (وحتى لها اسمها الخاص - "تدوين Yoda") ، وتساعد في عدد قليل من الحالات التي تم النظر فيها. - استخدم
const
على أوسع نطاق ممكن. مرة أخرى ، لا يساعد ذلك دائمًا. - اعتد على كتابة التعبيرات المنطقية الصحيحة:
if(x!=0)
بدلاً من if(x)
. (على الرغم من أنه يمكنك الوقوع في فخ أولويات المشغل هنا ، انظر المثال الثالث.) - كن منتبهًا للغاية.
1.2. التحويلات الضمنية
يشير C ++ إلى اللغات المكتوبة بشدة ، ولكن تحويلات النوع الضمني تستخدم على نطاق واسع لجعل الشفرة أقصر. يمكن أن تؤدي هذه التحويلات الضمنية في بعض الحالات إلى أخطاء.
أكثر التحويلات الضمنية المزعجة هي تحويلات من نوع رقمي أو مؤشر إلى bool
ومن bool
إلى int
. هذه التحولات (ضرورية للتوافق مع C) هي التي تسبب المشاكل الموضحة في القسم 1.1. التحويلات الضمنية التي من المحتمل أن تسبب خسارة في دقة البيانات الرقمية (تضييق التحويلات) ، على سبيل المثال ، من double
إلى int
ليست دائمًا مناسبة. في كثير من الحالات ، يقوم المترجم بإنشاء تحذير (خاصة عندما يكون هناك فقدان في دقة البيانات العددية) ، ولكن التحذير ليس خطأ. في C # ، تُحظر التحويلات بين الأنواع الرقمية bool
(حتى الصريحة) ، والتحويلات التي من المحتمل أن تتسبب في فقدان الدقة في البيانات الرقمية غالبًا ما تكون خطأ.
يمكن للمبرمج إضافة تحويلات ضمنية أخرى: (1) تحديد مُنشئ بمعلمة واحدة بدون الكلمة الأساسية explicit
؛ (2) تعريف عامل تحويل النوع. تكسر هذه التحولات ثغرات أمنية إضافية بناءً على مبادئ الكتابة القوية.
في C # ، يكون عدد التحويلات الضمنية المضمنة أصغر بكثير ؛ يجب الإعلان عن التحويلات الضمنية المخصصة باستخدام الكلمة الأساسية implicit
.
كيفية القتال:
- برنامج بدون تحذيرات.
- كن حذرا للغاية بشأن التصميمات الموصوفة أعلاه ، لا تستخدمها دون الحاجة الماسة.
2. تحليل الاسم
2.1. إخفاء المتغيرات في النطاقات المتداخلة
في C ++ ، تنطبق القاعدة التالية. دع
وفقًا لقواعد C ++ ، فإن المتغير
المعلن في
يخفي المتغير
المعلن عنه في
لا يجب أن يكون الإعلان الأول x
في كتلة: يمكن أن يكون عضوًا في فئة أو متغير عام ، بل يجب أن يكون مرئيًا في الكتلة
تخيل الموقف الآن عندما تحتاج إلى إعادة صياغة الكود التالي
عن طريق الخطأ ، يتم إجراء التغييرات:
والآن الكود "شيء ما يجري مع
من
" سيفعل شيئًا مع
من
! من الواضح أن كل شيء لا يعمل كما كان من قبل ، وإيجاد ما هو صعب للغاية في كثير من الأحيان. ليس عبثًا أنه في C # يُمنع إخفاء المتغيرات المحلية (على الرغم من أن أعضاء الفصل يمكنهم ذلك). لاحظ أن آلية إخفاء المتغيرات في شكل أو آخر تستخدم في جميع لغات البرمجة تقريبًا.
كيفية القتال:
- قم بتعريف المتغيرات في أضيق نطاق ممكن.
- لا تكتب كتل طويلة ومتداخلة بعمق.
- استخدم اصطلاحات التشفير للتمييز المرئي للمعرفات ذات النطاق المختلف.
- كن منتبهًا للغاية.
2.2. وظيفة الزائد
التحميل الزائد للوظائف هو ميزة متكاملة للعديد من لغات البرمجة و C ++ ليست استثناء. ولكن يجب اغتنام هذه الفرصة بعناية ، وإلا قد تتعرض لمشكلات. في بعض الحالات ، على سبيل المثال ، عندما يكون المُنشِئ مثقلًا ، لا يكون أمام المبرمج خيار ، ولكن في حالات أخرى ، يمكن تبرير رفض التحميل الزائد. ضع في اعتبارك المشكلات التي تنشأ عند استخدام الوظائف الزائدة.
إذا حاولت النظر في جميع الخيارات الممكنة التي قد تنشأ عند حل مشكلة الحمل الزائد ، فإن قواعد حل الحمل الزائد تكون معقدة للغاية ، وبالتالي يصعب التنبؤ بها. يتم تقديم التعقيد الإضافي من خلال وظائف القالب والحمل الزائد للمشغلين المدمجين. أضاف C ++ 11 مشاكل مع روابط rvalue وقوائم التهيئة.
يمكن إنشاء المشكلات بواسطة خوارزمية البحث للمرشحين لحل مشكلة التحميل الزائد في مناطق الرؤية المتداخلة. إذا وجد المترجم أي مرشحين في النطاق الحالي ، فسيتم إنهاء البحث الإضافي. إذا كان المرشحون الذين تم العثور عليهم غير مناسبين أو متضاربين أو محذوفين أو لا يمكن الوصول إليهم ، فسيتم إنشاء خطأ ، ولكن لا توجد محاولة أخرى للبحث. وفقط في حالة عدم وجود مرشحين في النطاق الحالي ، ينتقل البحث إلى النطاق التالي الأوسع. تعمل آلية إخفاء الاسم ، وهي تقريبًا نفس ما تمت مناقشته في القسم 2.1 ، انظر [Dewhurst].
يمكن أن تقلل وظائف التحميل الزائد من سهولة قراءة التعليمات البرمجية ، مما يعني إثارة الأخطاء.
يبدو أن استخدام الوظائف مع المعلمات الافتراضية هو استخدام الوظائف المحملة بشكل زائد ، على الرغم من وجود عدد أقل من المشاكل المحتملة بالطبع. لكن المشكلة مع ضعف القراءة والأخطاء المحتملة لا تزال قائمة.
بحذر شديد ، يجب استخدام الحمل الزائد والمعلمات الافتراضية للوظائف الافتراضية ، انظر القسم 5.2.
يدعم C # أيضًا التحميل الزائد للوظائف ، لكن قواعد حل التحميل الزائد تختلف قليلاً.
كيفية القتال:
- لا تسيء استخدام التحميل الزائد للوظائف ، وكذلك تصميم الوظائف باستخدام المعلمات الافتراضية.
- إذا كانت الوظائف محملة بشكل زائد ، فاستخدم التوقيعات التي لا تكون موضع شك عند حل الأحمال الزائدة.
- لا تعلن وظائف بنفس الاسم في النطاق المتداخل.
- لا تنس أن آلية الوظائف عن بعد (
=delete
) التي ظهرت في C ++ 11 يمكن استخدامها لحظر بعض خيارات التحميل الزائد.
3. المُنشئون ، المدمرون ، التهيئة ، الحذف
3.1. دالات عضو الفئة التي تم إنشاؤها بواسطة المحول البرمجي
إذا لم يحدد المبرمج وظائف أعضاء الفئة من القائمة التالية - المنشئ الافتراضي ، مُنشئ النسخ ، عامل تعيين النسخ ، المدمر - عندها يمكن للمترجم القيام بذلك من أجله. أضاف C ++ 11 مُنشئ نقل وعامل تعيين نقل إلى هذه القائمة. تسمى وظائف الأعضاء هذه وظائف الأعضاء الخاصة. يتم إنشاؤها فقط إذا تم استخدامها ، ويتم استيفاء الشروط الإضافية الخاصة بكل وظيفة. نلفت الانتباه إلى حقيقة أن هذا الاستخدام قد يتضح أنه مخفي تمامًا (على سبيل المثال ، عند تنفيذ الوراثة). إذا تعذر إنشاء الوظيفة المطلوبة ، فسيتم إنشاء خطأ. (باستثناء عمليات النقل ، يتم استبدالها بعمليات النسخ). وظائف الأعضاء التي تم إنشاؤها بواسطة المترجم عامة ويمكن تضمينها. يمكن الاطلاع على تفاصيل وظائف الأعضاء الخاصة في [Meyers2].
في بعض الحالات ، يمكن أن تكون هذه المساعدة من المترجم "خدمة تتحمل". يمكن أن يؤدي غياب وظائف الأعضاء الخاصة المخصصة إلى إنشاء نوع تافه ، وهذا بدوره يسبب مشكلة المتغيرات غير المهيأة ، انظر القسم 3.2. وظائف الأعضاء التي تم إنشاؤها هي عامة ، وهذا لا يتوافق دائمًا مع تصميم الفئات. في الفئات الأساسية ، يجب حماية المنشئ ؛ في بعض الأحيان ، من أجل تحكم أدق في دورة حياة الكائن ، هناك حاجة إلى مدمر محمي. إذا كان للفصل واصف مورد خام كعضو ويمتلك هذا المورد ، فإن المبرمج يحتاج إلى تطبيق مُنشئ نسخ ، عامل تعيين نسخ ، ومدمّر. إن ما يسمى بـ "قاعدة الثلاثة الكبار" معروفة جيدًا ، والتي تنص على أنه إذا قام المبرمج بتعريف واحدة على الأقل من العمليات الثلاث - منشئ النسخ أو عامل تعيين النسخ أو المدمر - فيجب عليه تحديد جميع العمليات الثلاث. إن منشئ الحركة وعامل تعيين النقل الذي تم إنشاؤه بواسطة المترجم بعيدًا أيضًا عما تحتاجه دائمًا. يؤدي المدمر الناتج عن المحول البرمجي في بعض الحالات إلى مشاكل دقيقة للغاية ، وقد ينتج عن ذلك تسرب الموارد ، انظر القسم 3.7.
يمكن للمبرمج منع إنشاء وظائف الأعضاء الخاصة ، في C ++ 11 من الضروري استخدام بناء "=delete"
عند التصريح ، في C ++ 98 الإعلان عن وظيفة العضو المقابلة الخاصة وعدم تعريفها.
إذا كان المبرمج مرتاحًا لوظائف الأعضاء التي تم إنشاؤها بواسطة المترجم ، فيمكنه في C ++ 11 الإشارة إلى ذلك بشكل صريح ، وليس فقط إسقاط الإعلان. للقيام بذلك ، يجب عليك استخدام بناء "=default"
عند الإعلان ، في حين أن قراءة التعليمات البرمجية بشكل أفضل وظهور ميزات إضافية تتعلق بإدارة مستوى الوصول.
في C # ، يمكن أن يولد المحول البرمجي مُنشئًا افتراضيًا ، عادةً لا يسبب هذا أي مشاكل.
كيفية القتال:
- السيطرة على المترجم توليد وظائف الأعضاء الخاصة. إذا لزم الأمر ، نفذها بنفسك أو حظرها.
3.2. متغيرات غير مهيأة
يمكن تسمية المنشئين والمدمرين بالعناصر الأساسية لنموذج كائن C ++. عند إنشاء كائن ، يجب استدعاء المنشئ ، وعند الحذف ، يتم استدعاء المدمر. لكن مشكلات التوافق مع C فرضت بعض الاستثناءات ، ويسمى هذا الاستثناء الأنواع التافهة. يتم تقديمها لمحاكاة أنواع sichny ودورة حياة syshny من المتغيرات ، دون استدعاء إلزامي من المنشئ والمدمّر. كود C ، إذا تم تجميعه وتنفيذه في C ++ ، يجب أن يعمل تمامًا كما هو الحال في C. تتضمن الأنواع التافهة الأنواع الرقمية ، والمؤشرات ، والتعداد ، بالإضافة إلى الفئات والهياكل والنقابات والمصفوفات التي تتكون من أنواع تافهة. يجب أن تستوفي الفئات والهياكل بعض الشروط الإضافية: عدم وجود مُنشئ مخصص ، مُدمِّر ، نسخ ، وظائف افتراضية. بالنسبة لفئة تافهة ، يمكن للمترجم إنشاء مُنشئ افتراضي ومدمر. يقوم المُنشئ الافتراضي بتصفير الكائن ، ولا يقوم المدمر بأي شيء. ولكن سيتم إنشاء هذا المُنشئ واستخدامه فقط إذا تم استدعاؤه بشكل صريح عند تهيئة المتغير. لن يتم تحديد متغير من نوع تافه إذا لم تستخدم نوعًا مختلفًا من التهيئة الصريحة. تعتمد صيغة التهيئة على نوع وسياق تعريف المتغير. تتم تهيئة المتغيرات الثابتة والمحلية عند الإعلان عنها. بالنسبة للفصل ، تتم تهيئة الفئات الأساسية الفورية وأعضاء الفئة غير الثابتة في قائمة تهيئة المنشئ. (C ++ 11 يسمح لك بتهيئة أعضاء الفئة غير الثابتة عند الإعلان ، انظر لاحقًا.) بالنسبة للكائنات الديناميكية ، يقوم التعبير new T()
بإنشاء كائن تمت تهيئته بواسطة المُنشئ الافتراضي ، لكن new T
للأنواع التافهة يُنشئ كائنًا غير مهيأ. عند إنشاء صفيف ديناميكي من نوع تافه ، new T[N]
، ستكون عناصره دائمًا غير مهيأة. إذا تم إنشاء أو توسيع مثيل std::vector<T>
ولم يتم توفير المعلمات من أجل التهيئة الصريحة للعناصر ، عندئذٍ يتم ضمان استدعاء المُنشئ الافتراضي. يقدم C ++ 11 صيغة جديدة للتهيئة - باستخدام الأقواس المتعرجة. يعني وجود زوج من الأقواس الفارغة التهيئة باستخدام المُنشئ الافتراضي. هذا التهيئة ممكن في كل مكان حيث يتم استخدام التهيئة التقليدية ، إلى جانب أنه أصبح من الممكن تهيئة أعضاء غير ثابتين في الفصل عند الإعلان ، والذي يحل محل التهيئة في قائمة التهيئة للمنشئ.
يتم إنشاء متغير غير مهيأ على النحو التالي: إذا تم تعريفه في نطاق namespace
(عالميًا) ، فسيكون له جميع البتات صفر ، إذا كان محليًا أو تم إنشاؤه ديناميكيًا ، فسوف يتلقى مجموعة عشوائية من البتات. من الواضح أن استخدام مثل هذا المتغير يمكن أن يؤدي إلى سلوك غير متوقع للبرنامج.
صحيح أن التقدم لا يقف ساكناً ، فالمجمعون الحديثون ، في بعض الحالات ، يكتشفون متغيرات غير مهيأة ويلقون خطأ. يكتشف محللو الكود غير المهيئين بشكل أفضل.
تحتوي مكتبة C ++ 11 القياسية على قوالب تسمى خصائص النوع (ملف الرأس <type_traits>
). يسمح لك أحدها بتحديد ما إذا كان النوع تافهًا. يكون التعبير std::is_trivial<>::value
true
إذا كان T
تافهًا و false
.
غالبًا ما تسمى الهياكل Sysylic البيانات القديمة البسيطة (POD). يمكننا أن نفترض أن POD و "النوع التافه" هما مصطلحان متكافئان تقريبًا.
في C # ، تتسبب المتغيرات غير المهيأة في حدوث خطأ ؛ ويتم التحكم في ذلك من قبل المترجم. يتم تهيئة حقول الكائنات من النوع المرجعي افتراضيًا إذا لم يتم إجراء التهيئة الصريحة. تتم تهيئة حقول الكائنات من النوع المهم إما بشكل افتراضي أو يجب تهيئة الكل بشكل صريح.
كيفية القتال:
- لديهم عادة تهيئة متغير بشكل صريح. يجب أن "يقطع العين" متغير غير مهيأ.
- قم بتعريف المتغيرات في أضيق نطاق ممكن.
- استخدم محللات التعليمات البرمجية الثابتة.
- لا تصمم أنواعًا تافهة. للتأكد من أن النوع ليس تافهًا ، يكفي تعريف مُنشئ مخصص.
3.3. إجراء التهيئة للفصول الأساسية وأعضاء الفئة غير الثابتة
عند تنفيذ مُنشئ الصف ، تتم تهيئة الفئات الأساسية الفورية وأعضاء الفئة غير الثابتة. يتم تحديد ترتيب التهيئة بالمعيار: أولاً ، الفئات الأساسية بالترتيب الذي تم التصريح بها في قائمة الفئات الأساسية ، ثم الأعضاء غير الثابتين في الفئة في ترتيب الإعلان. إذا لزم الأمر ، فإن التهيئة الصريحة للفئات الأساسية والأعضاء غير الثابتة تستخدم قائمة التهيئة للمنشئ. لسوء الحظ ، لا يلزم أن تكون العناصر في هذه القائمة بالترتيب الذي تحدث فيه التهيئة. يجب أن يؤخذ هذا في الاعتبار إذا كانت عناصر القائمة تستخدم ، أثناء التهيئة ، مراجع لعناصر القائمة الأخرى. عند الخطأ ، قد يكون الرابط لكائن لم تتم تهيئته بعد. يسمح لك C ++ 11 بتهيئة أعضاء الفصل غير الثابت عند الإعلان (باستخدام الأقواس المتعرجة). في هذه الحالة ، لا تحتاج إلى التهيئة في قائمة التهيئة للمنشئ وتتم إزالة المشكلة جزئيًا.
في C # ، تتم تهيئة الكائن على النحو التالي: أولاً تتم تهيئة الحقول ، من الكائن الفرعي الأساسي إلى المشتق الأخير ، ثم يتم استدعاء المنشئين بنفس الترتيب. لا تحدث المشكلة الموصوفة.
كيفية القتال:
- احتفظ بقائمة تهيئة المنشئ بترتيب التصريح.
- حاول أن تجعل تهيئة الطبقات الأساسية وأعضاء الفصل مستقلة.
- استخدم التهيئة للأعضاء غير الثابتة عند الإعلان.
3.4. إجراء التهيئة لأعضاء الفئة الثابتة والمتغيرات العالمية
تتم تهيئة أعضاء الفئة الثابتة ، بالإضافة إلى المتغيرات المحددة في namespace
النطاق (عالميًا) في وحدات الترجمة (الملفات) المختلفة ، بالترتيب الذي يحدده التنفيذ. يجب أن يؤخذ هذا في الاعتبار إذا استخدمت هذه المتغيرات مراجع لبعضها البعض أثناء التهيئة. قد يكون الرابط إلى متغير غير مهيأ.
كيفية القتال:
- اتخاذ تدابير خاصة لمنع هذا الوضع. على سبيل المثال ، استخدم المتغيرات الثابتة المحلية (singleton) ، يتم تهيئتها عند الاستخدام الأول.
3.5. الاستثناءات في المدمرات
يجب ألا يدمر المدمر الاستثناءات. إذا انتهكت هذه القاعدة ، يمكنك الحصول على سلوك غير محدد ، غالبًا ما يكون إنهاء غير طبيعي.
كيفية القتال:
- تجنب رمي الاستثناءات في المدمر.
3.6. إزالة الكائنات والمصفوفات الديناميكية
إذا تم إنشاء كائن ديناميكي من نوع T
T* pt = new T();
ثم يتم حذفه باستخدام عامل delete
delete pt;
إذا تم إنشاء مصفوفة ديناميكية
T* pt = new T[N];
ثم يتم حذفه باستخدام عامل delete[]
delete[] pt;
إذا لم تتبع هذه القاعدة ، يمكنك الحصول على سلوك غير محدد ، أي أنه يمكن أن يحدث أي شيء: تسرب للذاكرة ، أو تعطل ، وما إلى ذلك. راجع [Meyers1] للحصول على التفاصيل.
كيفية القتال:
- استخدم نموذج
delete
الصحيح.
3.7. الحذف عندما يكون تصريح الفصل الدراسي غير مكتمل
يمكن أن تثير عامل عامل delete
النهمة مشاكل معينة ؛ يمكن تطبيقها على مؤشر من نوع void*
أو على مؤشر لفئة لديها تصريح غير مكتمل (استباقي). عامل delete
المطبق على مؤشر على فئة ما هو عملية من مرحلتين ؛ أولاً ، يتم استدعاء المدمر ، ثم يتم تحرير الذاكرة. delete
, ( ). فكر في مثال:
class X;
, ,
delete
X
. Visual Studio :
warning C4150: deletion of pointer to incomplete type 'X'; no destructor called
X
CreateX()
, , CreateX()
, new
, Foo()
, . , , .
, -. , . , , , , . [Meyers2].
:
4. ,
4.1.
++ , . . . , 1.1.
هنا مثال:
std::out<<c?x:y;
(std::out<<c)?x:y;
std::out<<(c?x:y);
, , .
. <<
?:
std::out
void*
. ++ , . -, , . ?:
. , ( ).
: x&f==0
x&(f==0)
, (x&f)==0
, , , . - , , , , .
. / . / , /, . , x/4+1
x>>2+1
, x>>(2+1)
, (x>>2)+1
, .
C# , C++, , - .
:
4.2.
++ , . . , , . 4.1. — +
+=
. . , : ,
(), &&
, ||
. , (-), (short-circuit evaluation semantics), , . & ( ). & , .. .
, - (-) , . .
- , , . . [Dewhurst].
C# , , , .
:
4.3.
++ , . ( : ,
(), &&
, ||
, ?:
.) , , , . :
int x=0; int y=(++x*2)+(++x*3);
y
.
, . .
class X; class Y; void Foo(std::shared_ptr<X>, std::shared_ptr<Y>);
Foo()
:
Foo(std::shared_ptr<X>(new X()), std::shared_ptr<Y>(new Y()));
: X
, Y
, std::shared_ptr<X>
, std::shared_ptr<Y>
. Y
, X
.
:
auto p1 = std::shared_ptr<X>(new X()); auto p2 = std::shared_ptr<Y>(new Y()); Foo(p1, p2);
std::make_shared<Y>
( , ):
Foo(std::make_shared<X>(), std::make_shared<Y>());
. [Meyers2].
:
5.
5.1.
++98 , ( ), , ( , ). virtual
, , . ( ), , , . , , . , ++11 override
, , , . .
:
5.2.
. , , . . . [Dewhurst].
:
5.3.
, , . , , post_construct pre_destroy. , — . . , : ( ) . (, , .) , ( ), ( ). . [Dewhurst]. , , .
— - .
, C# , , , . C# : , , . , ( , ).
:
5.4.
, , delete
. , - .
:
6.
— C/C++, . . . « ».
C# unsafe mode, .
6.1.
/++ , : strcpy()
, strcat()
, sprinf()
, etc. ( std::vector<>
, etc.) , . (, , , . . Checked Iterators MSDN.) , : , , ; , .
C#, unsafe mode, .
:
- , .
- .
- z-terminated ,
_s
(. ).
6.2. Z-terminated
, . , :
strncpy(dst,src,n);
strlen(src)>=n
, dst
(, ). , , . . — . if(*str)
, if(strlen(str)>0)
, . [Spolsky].
C# string
.
:
6.3.
...
. printf
- , C. , , , , . , .
C# printf
, .
:
7.
7.1.
++ , , , . هنا مثال:
const int N = 4, M = 6; int x,
:
int
;int
;N
int
;N
int
;- ,
char
int
; - ,
char
int
; - ,
char
int
; N
, char
int
;N
int
;M
N
int
;- ,
char
, long
int
.
, . ( .)
*
&
. ( .)
typedef
( using
-). , :
typedef int(*P)(long); PH(char);
, .
C# , .
:
7.2.
.
class X { public: X(int val = 0);
X x(5);
x
X
, 5.
X x();
x
, X
, x
X
, . X
, , :
X x; X x = X(); X x{};
, , , . [Sutter].
, , C++ ( ). . ( C++ .)
, , , , .
C# , , .
:
8.
8.1. inline
ODR
, inline
— . , . inline
(One Defenition Rule, ODR). . , . , ODR. static
: , , . static
inline
. , , ODR, . , . - , -. .
:
- «»
inline
. namespace
. , . - —
namespace
.
8.2.
. . , , , , .
:
- , .
- , : () , -.
using
-: using namespace
, using
-.- .
8.3. switch
— break
case
. ( .) C# .
:
8.4.
++ , — , — . ( class
struct
) , . ( , # Java.) — , .
- , . (
std::string
, std::vector
, etc.), , . - , , .
- , (slicing), , .
, , , . . , , . , . . — ( =delete
), — explicit
.
C# , .
:
8.5. إدارة الموارد
++ . , . - ( ), ++11 , , , .
C++ .
C# , . , . (using-) Basic Dispose.
:
8.6.
«» . , , C++ , STL- - .
. . , . . «», . COM- . (, .) , C++ . — . . . , («» ) , . .
# , . — .
:
8.7.
C++ , : , , . ( !) . , . , . , , . (, .)
C ( ), C++ C ( extern "C"
). C/C++ .
-. #pragma
- , , .
, , , .
, , COM. COM-, , ( , ). COM , , .
C# . , — , C#, C# C/C++.
:
8.8.
, . , . C++ . بدلاً من ذلك
#define XXL 32
const int XXL=32;
. inline
.
# ( ).
:
9.
- . . . , .
- .
- . ++ — ++11/14/17.
- - , - .
- .
المراجع
[Dewhurst]
, . C++. .: . . — .: , 2012.
[Meyers1]
, . C++. 55 .: . . — .: , 2014.
[Meyers2]
, . C++: 42 C++11 C++14.: . . — .: «.. », 2016.
[Sutter]
, . C++.: . . — : «.. », 2015.
[Spolsky]
, . .: . . — .: -, 2008.