سؤال

لم أستخدم لغة C++ كثيرًا في الماضي، وقمت مؤخرًا باستخدام الكثير من لغة C#، وأجد صعوبة في العودة إلى أساسيات لغة C++ مرة أخرى.يعد هذا أمرًا صعبًا بشكل خاص نظرًا لأن العمل يتطلب عدم استخدام أي من بنيات C++ الأكثر سهولة، لذلك يجب أن تكون جميع السلاسل عبارة عن char *'s، ولا يوجد أي شرط لقوائم STL.

ما أحاول فعله حاليًا هو إنشاء قائمة من السلاسل، وهو أمر لن يستغرق مني وقتًا على الإطلاق باستخدام STL أو في C#.في الأساس أريد الحصول على وظيفة مثل:

char **registeredNames = new char*[numberOfNames];

ثم،

RegisterName(const * char const name, const int length)
{
    //loop to see if name already registered snipped
    if(notFound)
    {
        registeredNames[lastIndex++] = name;
    }

}

أو لو كان C#...

if(!registeredNames.Contains(name))
{
    registeredNames.Add(name);
}

وأنا أدرك أنه لا يعمل.أعلم أن الطبيعة الثابتة للمتغيرات التي تم تمريرها (مؤشر const وسلسلة const) تجعل الأمر صعبًا إلى حد ما، لكن مشكلتي الأساسية هي أنني كنت دائمًا أتجنب هذا الموقف في الماضي باستخدام قوائم STL وما إلى ذلك.لذلك لم أضطر أبدًا إلى العمل حول هذا الموضوع!

هل كانت مفيدة؟

المحلول

ربما ستحتاج إلى استخدام strcmp لمعرفة ما إذا كانت السلسلة مخزنة بالفعل:

for (int index=0; index<=lastIndex; index++)
{
  if (strcmp(registeredNames[index], name) == 0)
  {
    return; // Already registered
  }
}

ثم إذا كنت تريد حقًا تخزين نسخة من السلسلة، فستحتاج إلى تخصيص مخزن مؤقت ونسخ الأحرف فيه.

char* nameCopy = malloc(length+1);
strcpy(nameCopy, name);
registeredNames[lastIndex++] = nameCopy;

لم تذكر ما إذا كان إدخالك قد تم إنهاؤه بـ NULL - إذا لم يكن الأمر كذلك، فستلزم مزيد من العناية، ولن يكون strcmp/strcpy مناسبًا.

نصائح أخرى

هناك أسباب مشروعة قد تؤدي إلى تجنب المحكمة الخاصة بلبنان.عند العمل في بيئات ثابتة حيث تكون الذاكرة أو السرعة أمرًا ممتازًا، يكون من الصعب أحيانًا معرفة ما يحدث أسفل الغطاء باستخدام STL.نعم، يمكنك كتابة مخصصات الذاكرة الخاصة بك، ونعم، السرعة ليست مشكلة بشكل عام، ولكن هناك اختلافات بين تطبيقات STL عبر الأنظمة الأساسية، وقد تكون هذه الاختلافات دقيقة ومن المحتمل أن تكون عربات التي تجرها الدواب.ربما تكون الذاكرة هي أكبر ما يقلقني عند التفكير في استخدامها.

الذاكرة ثمينة، وكيفية استخدامها يجب أن تخضع لرقابة صارمة.ما لم تكن قد سلكت هذا الطريق، فقد لا يكون هذا المفهوم منطقيًا، لكنه صحيح.نحن نسمح باستخدام STL في الأدوات (خارج رمز اللعبة)، ولكنه محظور داخل اللعبة الفعلية.مشكلة أخرى ذات صلة هي حجم الكود.لست متأكدًا إلى حد ما من مقدار مساهمة STL في الحجم القابل للتنفيذ، ولكننا شهدنا زيادات ملحوظة في حجم الكود عند استخدام STL.حتى لو كان ملفك القابل للتنفيذ أكبر بمقدار 2M "فقط"، فهذا يعني أن ذاكرة الوصول العشوائي أقل بمقدار 2M لشيء آخر في لعبتك.

STL جميلة بالتأكيد.ولكن يمكن إساءة استخدامها من قبل المبرمجين الذين لا يعرفون ماذا يفعلون.هذا ليس مقصودًا، ولكنه يمكن أن يقدم مفاجآت سيئة عندما لا ترغب في رؤيتها (مرة أخرى، انتفاخ الذاكرة ومشكلات الأداء)

أنا متأكد من أنك قريب من الحل الخاص بك.

for ( i = 0; i < lastIndex; i++ ) {
    if ( !strcmp(&registeredNames[i], name ) {
        break;    // name was found
    }
}
if ( i == lastIndex ) {
    // name was not found in the registeredNames list
    registeredNames[lastIndex++] = strdup(name);
}

قد لا ترغب في استخدام strdup.هذا مجرد مثال لكيفية تخزين الاسم في المثال الخاص بك.قد ترغب في التأكد من أنك لا تريد تخصيص مساحة للاسم الجديد بنفسك، أو استخدام بعض بنية الذاكرة الأخرى التي قد تكون متاحة بالفعل في تطبيقك.

ومن فضلك، لا تكتب فئة سلسلة.لقد اعتبرت فئات السلسلة ربما أسوأ مثال على كيفية عدم إعادة هندسة بنية C الأساسية في C++.نعم، يمكن لفئة السلسلة إخفاء الكثير من التفاصيل الرائعة عنك، لكن أنماط استخدام الذاكرة الخاصة بها فظيعة، ولا تتلاءم جيدًا مع وحدة التحكم (على سبيل المثال.بيئة PS3 أو 360، إلخ).منذ حوالي 8 سنوات فعلنا نفس الوقت.أكثر من 200000 عملية تخصيص للذاكرة قبل أن نصل إلى القائمة الرئيسية.كانت الذاكرة مجزأة بشكل رهيب ولم نتمكن من جعل بقية اللعبة تتناسب مع البيئة الثابتة.لقد انتهينا من تمزيقها.

يعد التصميم الصفي أمرًا رائعًا لبعض الأشياء، لكن هذه ليست واحدة منها.هذا رأي، لكنه يعتمد على تجربة العالم الحقيقي.

إذا كانت قابلية النقل مشكلة، فقد ترغب في التحقق من ذلك STLport.

لماذا لا يمكنك استخدام المحكمة الخاصة بلبنان؟

على أي حال، أود أن أقترح عليك تنفيذ فئة سلسلة بسيطة وقوالب القائمة الخاصة بك.وبهذه الطريقة يمكنك استخدام نفس الأساليب التي تستخدمها عادةً وإبقاء المؤشر وإدارة الذاكرة مقتصرة على تلك الفئات.إذا قمت بتقليد المحكمة الخاصة بلبنان، سيكون أفضل.

إذا كنت لا تستطيع حقًا استخدام stl (ويؤسفني الاعتقاد بأن ذلك كان صحيحًا عندما كنت في صناعة الألعاب) فهل لا يمكنك إنشاء فئة السلسلة الخاصة بك؟أبسط فئة من فئات السلسلة هي تخصيص الذاكرة عند البناء والتخصيص، والتعامل مع الحذف في أداة التدمير.يمكنك لاحقًا إضافة المزيد من الوظائف حسب حاجتك إليها.محمول تمامًا وسهل جدًا في الكتابة واختبار الوحدة.

يتطلب العمل مع char* العمل مع وظائف C.في حالتك، ما تحتاجه حقًا هو نسخ السلاسل الموجودة حولك.لمساعدتك، لديك وظيفة strndup.ثم سيكون عليك كتابة شيء مثل:

void RegisterName(const char* name)
{
  // loop to see if name already registered snipped
  if(notFound)
  {
    registerNames[lastIndex++] = stdndup(name, MAX_STRING_LENGTH);
  }
}

يفترض هذا الرمز أن المصفوفة الخاصة بك كبيرة بما يكفي.

بالطبع، الأفضل هو تنفيذ السلسلة والمصفوفة والقائمة الخاصة بك بشكل صحيح، ...أو لإقناع رئيسك في العمل بأن المحكمة الخاصة بلبنان لم تعد شريرة بعد الآن!

يحرر:أعتقد أنني أساءت فهم سؤالك.لا توجد مشكلة ثبات في هذا الكود الذي أعرفه.

أفعل هذا من رأسي ولكن يجب أن يكون صحيحًا:

static int lastIndex = 0;
static char **registeredNames = new char*[numberOfNames];

void RegisterName(const * char const name)
{
    bool found = false;
    //loop to see if name already registered snipped
    for (int i = 0; i < lastIndex; i++)
    {
        if (strcmp(name, registeredNames[i] == 0))
        {
            found = true;
            break;
        }
    }

    if (!found)
    {
        registeredNames[lastIndex++] = name;
    }
}

أستطيع أن أفهم سبب عدم قدرتك على استخدام STL - فمعظمهم يقومون بتضخيم الكود الخاص بك بشكل رهيب.ولكن هناك تطبيقات لمبرمجي الألعاب بواسطة مبرمجي الألعاب - ردستل هي إحدى هذه المكتبات.

استخدام:

const char **registeredNames = new const char * [numberOfNames];

سيسمح لك بتعيين أ const * char const إلى أحد عناصر المصفوفة

فقط من باب الفضول، لماذا "يفرض العمل أنه لا يمكن استخدام أي من بنيات C++ الأكثر سهولة"؟

جميع الأساليب المقترحة صالحة، وجهة نظري هي أنه إذا كانت الطريقة التي تتبعها لغة C# جذابة، فقم بإنشاء فئات/واجهات خاصة بك لتقديم نفس التجريد، أي.فئة قائمة مرتبطة بسيطة مع الأساليب التي تحتوي على وإضافة، باستخدام نموذج التعليمات البرمجية المقدمة من الإجابات الأخرى، يجب أن يكون هذا بسيطًا نسبيًا.

أحد الأشياء الرائعة في C++ بشكل عام هو أنه يمكنك جعلها تبدو وتتصرف بالطريقة التي تريدها، إذا كانت لغة أخرى لديها تنفيذ رائع لشيء ما، فيمكنك عادةً إعادة إنتاجه.

لقد استخدمت فئة السلسلة هذه لسنوات.

http://www.robertnz.net/string.htm

إنه يوفر عمليًا جميع ميزات سلسلة STL ولكن يتم تنفيذه كطبق حقيقي وليس قالبًا ولا يستخدم STL.

هذه حالة واضحة لكيفية قيامك بالبدء بنفسك.وتفعل الشيء نفسه بالنسبة لفئة ناقلات.

  • افعل ذلك باستخدام برمجة الاختبار الأول.
  • أبقيها بسيطة.

تجنب مرجع حساب المخزن المؤقت للسلسلة إذا كنت في بيئة MT.

إذا لم تكن قلقًا بشأن الاصطلاحات وترغب فقط في إنجاز المهمة، فاستخدم realloc.أفعل هذا النوع من الأشياء للقوائم طوال الوقت، ويكون الأمر كالتالي:

T** list = 0;
unsigned int length = 0;

T* AddItem(T Item)
{
 list = realloc(list, sizeof(T)*(length+1));
 if(!list) return 0;
 list[length] = new T(Item);
 ++length;
 return list[length];
}

void CleanupList()
{
 for(unsigned int i = 0; i < length; ++i)
 {
  delete item[i];
 }
 free(list)
}

هناك المزيد الذي يمكنك القيام به، على سبيل المثال.إعادة التخصيص فقط في كل مرة يتضاعف فيها حجم القائمة، ووظائف إزالة العناصر من القائمة حسب الفهرس أو عن طريق التحقق من المساواة، وإنشاء فئة قالب للتعامل مع القوائم وما إلى ذلك ...(لدي واحدة كتبتها منذ زمن طويل وأستخدمها بنفسي دائمًا ...لكن للأسف أنا في العمل ولا أستطيع نسخه ولصقه هنا).لكي نكون صادقين تمامًا، ربما لن يتفوق هذا على أداء STL المعادل، على الرغم من أنه قد يساوي أدائه إذا كنت تقوم بالكثير من العمل أو كان لديك تنفيذ ضعيف بشكل خاص لـ STL.

من المزعج أن لغة C++ لا تحتوي على عامل تجديد/تغيير حجم ليحل محل إعادة التخصيص، وهو ما سيكون مفيدًا للغاية.

أوه، وأعتذر إذا كان الكود الخاص بي مليئًا بالأخطاء، فقد قمت للتو بسحبه من الذاكرة.

لا تزال صحة const صحيحة بغض النظر عما إذا كنت تستخدم STL أم لا.أعتقد أن ما تبحث عنه هو جعل الأسماء المسجلة أ const char ** حتى يتم التكليف به registeredNames[i] (وهو أ const char *) يعمل.

علاوة على ذلك، هل هذا حقًا ما تريد أن تفعله؟يبدو أن عمل نسخة من السلسلة ربما يكون أكثر ملاءمة.

علاوة على ذلك، لا ينبغي أن تفكر في تخزين هذا في قائمة نظرًا للعملية التي تقوم بها عليها، سيكون من الأفضل وجود مجموعة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top