هل يشير "& s [0] إلى الأحرف المتجاورة في Std :: String؟

StackOverflow https://stackoverflow.com/questions/1986966

  •  22-09-2019
  •  | 
  •  

سؤال

أقوم ببعض أعمال الصيانة وركضت شيئًا مثل ما يلي:

std::string s;
s.resize( strLength );  
// strLength is a size_t with the length of a C string in it. 

memcpy( &s[0], str, strLength );

أعلم أن استخدام & s [0] سيكون آمنًا إذا كان ناقل STD :: ، لكن هل هذا استخدام آمن لـ Std :: String؟

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

المحلول

لا يضمن تخصيص STD :: سلسلة متداولة بموجب معيار C ++ 98/03 ، ولكن C ++ 11 يجبرها على أن تكون. في الممارسة العملية ، لا أنا ولا عشب سوتر تعرف على تطبيق لا يستخدم التخزين المتجاوب.

لاحظ أن &s[0] يضمن الشيء دائمًا العمل وفقًا لمعايير C ++ 11 ، حتى في حالة السلسلة ذات الطول 0. لن يكون مضمونًا إذا فعلت str.begin() أو &*str.begin(), ، ولكن ل &s[0] المعيار يحدد operator[] مثل:

عائدات: *(begin() + pos) لو pos < size(), ، وإلا إشارة إلى كائن من النوع T مع القيمة charT(); ؛ لا يجوز تعديل القيمة المشار إليها

الاستمرار في ، data() يعرف ب:

عائدات: مؤشر p مثل ذلك p + i == &operator[](i) لكل i في [0,size()].

(لاحظ الأقواس المربعة في كلا طرفي النطاق)


تنويه: لم يضمن التحويل المسبق C ++ 0x &s[0] للعمل مع سلاسل بطول صفرية (في الواقع ، كان سلوكًا غير محدد بشكل صريح) ، وشرحت المراجعة القديمة لهذه الإجابة هذا ؛ تم إصلاح هذا في المسودات القياسية اللاحقة ، لذلك تم تحديث الإجابة وفقًا لذلك.

نصائح أخرى

من الناحية الفنية ، لا ، منذ ذلك الحين std::string ليس مطلوبًا لتخزين محتوياته بشكل متجاور في الذاكرة.

ومع ذلك ، في جميع التطبيقات تقريبًا (كل تنفيذ أدركه) ، يتم تخزين المحتويات بشكل متجاور وهذا "سيعمل".

إنه آمن للاستخدام. أعتقد أن معظم الإجابات كانت صحيحة مرة واحدة ، لكن المعيار تغير. نقلاً من C ++ 11 Standard ، المتطلبات العامة basic_string [string.require, ، 21.4.1.5 ، يقول:

يجب تخزين الكائنات التي تشبه char في كائن basic_string بشكل متناغم. وهذا هو ، بالنسبة لأي كائن basic_string s ، الهوية &*(s.begin () + n) == &*s.begin () + n يجب أن تحتفظ بجميع قيم n بحيث 0 <= n <size ().

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

ليس من غير المرجح أن تم إجراء هذا التغيير في C ++ 11. يبدو أنني أتذكر أنه تمت إضافة نفس الضمان في المتجه ، والذي أصبح أيضًا مفيدًا جدًا البيانات() مؤشر مع هذا الإصدار.

امل ان يساعد.

يجب أن يلاحظ القراء أنه تم طرح هذا السؤال في عام 2009 ، عندما كان معيار C ++ 03 هو المنشور الحالي. تعتمد هذه الإجابة على هذا الإصدار من المعيار ، حيث std::stringق ليس مضمون لاستخدام سعة التخزين المتجاورة. نظرًا لعدم طرح هذا السؤال في سياق منصة معينة (مثل GCC) ، لا أقدم أي افتراضات حول منصة OP - على وجه الخصوص ، الطقس أم لا يستخدم التخزين المتكرر لـ string.

قانوني؟ ممكن و ممكن لا. آمن؟ ربما ، ولكن ربما لا. رمز جيد؟ حسنًا ، دعونا لا نذهب إلى هناك ...

لماذا لا تفعل فقط:

std::string s = str;

...أو:

std::string s(str);

...أو:

std::string s;
std::copy( &str[0], &str[strLen], std::back_inserter(s));

...أو:

std::string s;
s.assign( str, strLen );

?

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

std::string s( str ) ;

أو إذا تم تعيينه إلى كائن Std :: سلسلة موجود ، فقط:

s = str ;

ثم دع std :: سلسلة نفسها تحدد كيفية تحقيق النتيجة. إذا كنت ستذهب إلى هذا النوع من الهراء ، فقد لا تستخدم أيضًا Std :: String والتمسك به لأنك تعيد إدخال جميع الأخطار المرتبطة بالسلاسل C.

هذا عموما ليس آمن ، بغض النظر عما إذا كان يتم تخزين تسلسل السلسلة الداخلية في الذاكرة بشكل مستمر أم لا. قد يكون هناك العديد من تفاصيل التنفيذ الأخرى المتعلقة بكيفية تخزين التسلسل المتحكم به بواسطة std::string كائن ، إلى جانب الاستمرارية.

مشكلة عملية حقيقية في ذلك قد تكون ما يلي. التسلسل المتحكم فيه std::string ليس مطلوبًا لتخزينه كسلسلة منتهية الصفر. ومع ذلك ، في الممارسة العملية ، تختار العديد من التطبيقات (معظم؟) حجم العازلة الداخلية التي تضخّمها بمقدار 1 وتخزين التسلسل كسلسلة منتهية على أي حال لأنها تبسط تنفيذ c_str() الطريقة: ما عليك سوى إرجاع مؤشر إلى المخزن المؤقت الداخلي وقد انتهيت.

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

بمعنى آخر ، في بعض التطبيقات ، ربما يتعين عليك استخدامها strcpy, ، ليس memcpy لإجبار البيانات على التسلسل المتحكم فيه من هذا القبيل. بينما في بعض التطبيقات الأخرى يجب أن تستخدمها memcpy و لا strcpy.

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