התחליף של sprintf עם std::string

ברנדל

New member
שוב

בקשר לפוטיבליות כבר סיכמנו שאני מסכים. אני מדבר בקשר למימוש. GetBuffer זה נפלא!!. אתה שואל למה אז אני עונה, זה מאפשר לך לעבוד עם האוביקט בפונקציות. שמקבלות מצביע לא קבוע למחרוזת (על מנת למלא את המחרוזת בתוכן). זו הסיבה העיקרית. לא בשביל לעבוד עם הקרביים סתם אלא לסיבה ספציפית. מה גם שאם אתה מפחד להשתמש, אל תשתמש. התפקיד של פונקציות גישה זה בדיוק זה. לתת גישה לקרביים + הגבלות מסוימות לעיתים הגבלות של קריאה בלבד (פונקציות const) ולפעמים הגבלות של בדיקת כתיבה. בקשר לפונקציונליות של של אלגוריתמים , יד על הלב, כמה אתה כבר משתמש בזה. מתי עשית sort פעם אחרונה לאוביקט string ומיינת את סדר האותיות בו לקסיקוגרפית האלגוריתמים החשובים יותר שרלוונטים ממושים בתור פונקציות מחלקה, כגון UCASE (שניתן לממש ע"י אלגוריתם ב string). אז אם מדברים על חוקים ותכנות נכון, תגיד לי אתה האם פונקצייה שמשנה סטטוס מחלקה (גישה לקרביים פרטיים) כגון UCASE צריכה להיות חלק ממחלקה או חיצונית כמו האלגוריתמים (לא שיש לי בעיה איתם). אלגוריתמים נוספים כגון sort לא מעניינים בהקשר של מחרוזות. לעומת זאת פונקציונליות כגון trim, format שכן רלוונטית לא ממושת ב string. שוב אני חוזר, אני לא טוען שעדיף להשתמש ב CString אני מודע לבעיית השינויים שצפויים להיות מצד MicroSoft או פורטביליות שלא מאפשרת מעבר למערכת הפעלה שונה מבלי לשנות את הקוד. הדבר היחיד שאני טוען זה שמחלקת CString מייצגת את מטרתה וממומשת טוב יותר מזו של std. ותפסיקו להתווכח זה ברור!! ומה שאני עוד אומר, שהתגבשה בפורום מן התנשאות מעל הקוד שמופק ע"י מיקרוסופט הרבה פעמים בלי סיבה מוצדקת. להזכיר לכולם עדיין מדובר בחברת תוכנה לא קטנה שעשתה אי אלו דברים בחיים שלה, קצת respect. גם אני לא מת על דריסה והשתלטות, אבל מפה ועד לזלזל בפתרונות רק כי הם של microsoft הדרך ארוכה.
 

אלדד28

New member
"אם אתה מפחד להשתמש, אל תשתמש"

תגיד, כשאתה כותב CLASS, אתה רושם public בהתחלה וסוגר עניין? למה להשתמש ב-protected או ב-private, בכלל? ולגבי סיפא ההודעה שלך, למיקרוסופט אין הרבה דברים טובים מעבר למכונת השיווק המעולה שלהם, לצי הכתבים הטכניים המוכשרים שלהם, ולחוסר המוסריות המוחלטת שלהם כחברה. מה שבטוח, חברה שיש לה כל כך הרבה פרצות בטיחות וקריסות ובעיות - היא לא חברת תוכנה שמייצרת תוכנות איכותיות במיוחד. ספציפית לגבי CString, לא אמרתי שהמימוש חרא. הבעיה היא עם ה-DESIGN, הרבה לפני המימוש. הקונספט שלה גרוע, כי היא לא OOP-ית, והיא מאוד, מאוד ספציפית - היא נותנת לך להגיע לייצוג הפנימי שלה, שזה אחד ה-Don't-ים הגדולים ביותר שיש ב-OOP. אני חושב שזה פחות או יותר השיעור הראשון בהנדסת תוכנה מונחית עצמים באוניברסיטה.
 

voguemaster

New member
הייתה לי מה זה תגובה מוכנה לשיגור

אבל פתאום חזיז ורעם! וואחד ברק עשה לי REBOOT למחשב + למודם אלקטל
 

eyalbd

New member
אנסה לסכם

קודם כל string הוא דבר די פשוט. לומר זה טוב מזה או זה ממומש טוב מזה לא לעניין כאן. זמן רב השתמשתי במשהו פשוט מאד משלי שהשתמש בstrdup ו-free והכל היה בסדר גמור והוא ייצג את מטרתו מצויין. למחלקה CString יש תאימות טובה יותר ל *char. התאימות הזאת מכתיבה מימוש ספציפי ש std::string בגלל כלליותה לא יכולה להכתיב. std::string אמורה לרוץ על כל דבר לכן אי אפשר להכתיב. למשל אין דרישה לזיכרון רציף. מאחר שאין דרישה שכזאת *operator const char הוא לא מתאים. אחרת זו תהיה פעולה יקרה מאד או שיקרו תאונות למשל:
void func(const void*); CString s; f(s); // compiles but suspicious OR: void* p = malloc(len); CString s; if (p == s) { // compiles but suspicious }​
המחלקה std::string מתאימה יותר לשימוש עם הספריה הסטנדרטית. זה כולל IOSTREAMS איטרטורים אלגוריתמים ועוד. אין בה דרישות על המימוש. למשל ROPE של SGI שהוא בעל ממשק זהה לstd::string ממומש ללא זכרון רציף ועדיף במקרה של מחרוזות ארוכות מאד. ( rope בא עם GCC אם אתה מעוניין ללמוד יותר או לשחק קצת ) ל-std::string חסרות כמה פונקציות שיש ב CString ולהיפך. זה לא הופך אחת מהן טובה מהשניה. את מה ש-GetBuffer נותן אפשר לממש בקלות עי מערך לוקלי או ע"י vector. אין בעיה להתאים פונקציות לstd::string. השיטה של GetBuffer ו-ReleaseBuffer שימושית אבל היא מסוכנת כאשר משתמשים בקוד מודרני שעושה שימוש בexceptions. אם בין ה Get ל-Release יש exception אני מותיר מחלקה במצב לא מוגדר. במילים אחרות אני עלול לשבור class invariants שבכל מקרה זה לא קורה עם std::string. אפשר תמיד להשתמש ב buffer זמני כמו שכתבתי למעלה. חסר ל-std::string מספר פונקציות כמו למשל format, mid, right, trim וכו'. המימוש שלהן קל מאד. למעט format כל אחת מהן היא שתי שורות. כנ"ל לגבי upper או lower. אין שום מניעה שMS (או כל יצרן קומפיילר / ספרייה אחר) יוסיף אותן בתור extensions. זה שהמימוש קל לא עושה את std::string למשהו נפלא - זה פשוט קל! לגבי format -לא הוסיפו בכוונה כי הוא לא type safe והוא מהווה הזמנה לשגיאות printf כולל שגיאות שקשורות לאבטחה. לגבי פורטביליות - אפשר לממש את CString כולה ע"י std::string )עם כמה מגבלות) ראה קישור. פרוייקט boost ועוד פרוייקטים אחרים כותבים תוספות והרחבות לstd::string, ספריות GUI חדשות משתמשות בספרייה הסטנדרטית ולא במשהו משלהן. כל התוספות האלה בונות על עובדה אחת - הספריה הסטנדרטית ובתוכה std::string זמינות בכל מימוש של ++C. אם תשתמש רק במה שMFC מספקת אתה תגביל את עצמך במידה רבה ותצטרך להמציא את הגלגל מחדש בכל פעם שתתמודד עם בעיה חדשה. אין כל בעיה ואפילו רצוי להשתמש ב-CString כאשר אתה כותב תוכנית MFC. היא מתאימה יותר. לכל השאר, כדאי שתלמד את std::string ואת ההרחבות שמסתובבות ברשת - לדוגמא regular expressions או substring. אחרון חביב - חשוב על מחרוזת כעל סקלר ולא כעל וקטור של בתים. אם תתרגל לצורת החשיבה הזאת לא תצטרך להשתמש הרבה ב *char. אני כותב הרבה גם ב Perl שבה מחרוזת היא סקלר ואחד החלקים החזקים ביותר שלה הוא עיבוד טקסט! וכל זה מתבצע בלי לרדת לרמת ה *char או התו הבודד אלא להשתמש באופרטורים או פונקציות שהשפה נותנת. ב-++C השפה לא נותנת כלום אבל הספריה הסטנדרטית נותנת לך ים של אפשרויות לעיבוד טקסט בלי "לחשוב *char". כאשר אתה משתמש ב std::string קל יותר לעשות את הסוויץ'. CString לא מאפשר לך לעשות אותו כי הוא בנוי מלכתחילה לעבודה עם פונקציות *char ועם תאימות רבה יותר לפונקציות C. אייל
 

DNile

New member
הזמנה לבאגים? הכיצד?

ואני מניח שאלדד התכוון לstrlen מבחינת הערכת הגודל. CString בסופו של דבר עושה בדיוק בדיוק בדיוק מה שאלדד אמר - הוא מעריך את הגודל של הפרמטרים על פי אורכי המחרוזות ל%s, ולפי שאר הפרמטרים, ואח"כ מבצע vsprintf(או אחד מהפונקציות הדומות) למה לא להשתמש בCString אתה שואל? תשובה פשוטה למדי - מי אמר שהוא משתמש בMFC? מי אמר שהוא רץ על windows?
 

Milo M

New member
אלדד DNile

אלדד "אימה ופחד" זה ביטוי מספר ילדים מעולה. לא מצאתי מעולם דליפת זיכרון במחלקה CString אבל זה רק אני. יש סיבות אחרות לא להשתמש במחלקה זו שאחת מהם היא פורטוביליות. אשמח מאוד אם תביא הוכחה כלשהיא לדליפות זיכרון במחלקה כי אני משתמש בה מפעם לפעם. DNili איך אתה יודע איך CString ממומש? יש לך את קוד המקור אם כן אשמח לראות. בקשר לעובדה שיתכן והוא לא מריץ על WIN אתה צודק.
 

eyalbd

New member
יש את קוד המקור עם MFC

אפשר בעת ההתקנה להתקין עם קוד מקור. המחלקה CString לא באה בחשבון כי השואל שאל מפורשות על std::string. יש או אין דליפות זה לא משנה. CString היא חלק מספריה מהימים שלא היתה ספריה סטנדרטית ל ++C. היום יש ובה כדאי להשתמש. מי שממש רוצה CString על מערכות אחרות יכול להציץ בקישור המצורף.
 

eyalbd

New member
למה לי לעבוד קשה סתם?

כאשר vsnprintf עושה את זה יותר טוב ממני? הפונקציה שנתתי לא מוגבלת ל256 זה רק לאיטרציה הראשונה (ולרוב ביחידה כי זה בד"כ מספיק). אם זה לא מספיק אני יודע זאת מהערך שמחזירה vsnprintf ובמקרה כזה משתמש בהקצאה דינמית. פשוט, מהיר (כל זמן שאין צורך באיטרציה שניה), ובטוח.
 

ilankt

New member
איזה HEADER חסר לי?

error C2065: 'vsnprintf' : undeclared identifier error C2065: 'assert' : undeclared identifier​
 

eyalbd

New member
תנסה את זה

תחליף cstdarg ב- stdarg.h או שתוסיף namespace std בתחילת הפונקציה. לגבי assert חסר assert.h איזה קומפיילר יש לך? אני בדקתי ב gcc-3.3.1 אייל
 

ilankt

New member
עדיין יש שגיאה (ויותר מדי headers)

#include <string> #include <cstdarg> #include <vector> #include <iostream> #include <assert.h> using namespace std; std::string string_printf(const char* format, ...) { va_list arg_ptr; va_start(arg_ptr, format); char buf[256]; int size = vsnprintf(buf, sizeof buf, format, arg_ptr); assert(size >= 0); if (size < sizeof(buf)) return std::string(buf, buf + size); std::vector<char> buffer(size + 1); size = vsnprintf(&buffer[0], buffer.capacity(), format, arg_ptr); assert (size < buffer.capacity()); return std::string( buffer.begin(), buffer.begin() + size ); }​
שגיאה:
error C2065: 'vsnprintf' : undeclared identifier​
 

ahab

New member
stringstream?

פיספסתי משהו, או שהרבה יותר פשוט להשתמש ב-stringstream בשביל זה?
// stringstream::str #include <iostream> #include <sstream> #include <string> using namespace std; int main () { stringstream oss; string mystr; oss << "Sample string " << 54 << " bla bla"; mystr=oss.str(); cout << mystr; return 0; }​
 

DNile

New member
../images/Emo45.gif התכוונתי להגיד בדיוק את זה..

אבל אין לי סביבת עבודה מותקנת על המחשב, ואני אף פעם לא זוכר אם זה stringstream או strstream :)
 

eyalbd

New member
אכן זה תמיד עדיף

אבל השואל שאל על משהו דומה ל-printf בכל מקרה אני מעדיף iostreams על פני פורמט של printf
 
למעלה