المشكلات حذف صفيف ديناميكي ثنائي الأبعاد في C ++ (والذي يتم تخزينه في النهاية في ناقل)

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

سؤال

لذلك لدي صفيف ديناميكي ثنائي الأبعاد، أي محتوى أريد حرية تحريره عندما انتهيت منه. ومع ذلك، استمر في الركض في فساد كومة بعد التدريس. يعمل الرمز بشكل جيد (بالطبع مع تسرب الذاكرة) إذا كنت أعلق المدمرة. (Visual Studio 2005)

FrameData::FrameData(int width, int height)
{
    width_ = width;
    height_ = height;

    linesize[0] = linesize[1] = linesize[2] = linesize[3] = 0;

    // Initialise the 2d array
    // Note: uint8_t is used by FFMPEG (typedef unsigned char uint8_t)
    red = new uint8_t* [height];
    green = new uint8_t* [height];
    blue = new uint8_t* [height];

    for (int i=0; i < height; i++)
    {
        red[i] = new uint8_t [width];
        green[i] = new uint8_t [width];
        blue[i] = new uint8_t [width];
    }       
}

FrameData::~FrameData()
{

    // Delete each column
    for (int i=0; i < height_; i++)
    {           
        delete[] ((uint8_t*) red[i]);
        delete[] ((uint8_t*)green[i]);
        delete[] ((uint8_t*)blue[i]);       
    }

    // Final cleanup
    delete[] red;
    red = NULL;

    delete[] green;
    green = NULL;

    delete[] blue;
    blue = NULL;    
} 

ليس لدي أي فكرة عما هو الخطأ في الكود. الشيء الآخر الوحيد هو في مكان آخر، فعلت هذا في حلقة حيث حدث الحادث

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

هذا لا ينبغي أن يسبب أي مشكلة، أليس كذلك؟ إذا كنت أتذكر صحيحا، فإن Push_back يجعل نسخة بدلا من تخزين مؤشر أو مرجع.

ملاحظة. نعم، يجب أن تستخدم ناقلات. لكنني غير مسموح لي.

معلومات اضافية:

لم يتم تعريف المشغل = ونسخ المنشئ. أعتقد أن هذا سبب للمشكلة.

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

المحلول

مشكلتك هي كما كنت تخمن هنا:

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

يتخذ المتجه نسخا من العناصر التي تدفعها. ماذا لديك لنسختك و / أو operator= لفصلك؟ إذا لم يكن لديك أي شيء محدد، الإصدار الافتراضي الذي ينشئه التحويل البرمجي لك ببساطة إجراء نسخ من أعضاء فصلك. هذا سوف نسخ أعضاء المؤشر red, green و blue إلى مثيل جديد. ثم سيتم تدمير المثيل القديم الذي قمت بنسخه عندما يخرج من النطاق، مما يؤدي إلى حذف المؤشرات. سيتم بعد ذلك حذف مؤشرات غير صالحة لك في هذا المتجه إلى حذف هدف المؤشر.

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

على سبيل المثال، std::auto_ptr تحتوي الفئة على مؤشر خام - هي دلالات منشئ النسخ هو نقل ملكية المؤشر إلى الهدف.

ال boost::shared_ptr يحتوي الفصل على مؤشر خام - الدلالات هي مشاركة الملكية عن طريق العد المرجعي. هذه طريقة لطيفة للتعامل معها std::vectors تحتوي المؤشرات المشتركة على المؤشرات - ستتحكم المؤشرات المشتركة في الملكية لك.

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

نصائح أخرى

ما لم يكن لديك منشئ نسخ عميق ومشغل التعيين من فئة Frameata، فإن شعوري الأمعاء هو أن برنامج التحويل البرمجي يولد منشئ نسخة لاستخدامه مع push_back. سيقوم منشئو النسخ المستندون تلقائيا بإنشاء نسخ في بعض الوقت، مما سيؤدي إلى نسخ ضحل في هذه الحالة. لسوء الحظ، لا يعرف Destructor الخاص بك عن النسخة حتى أثناء النسخ، فهناك فرصة جيدة يتم تدمير نسخة مؤقتة من Freameata وستستفيد كل بياناتك إليها.

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

أفضل طريقة للعثور على مشاكل مثل هذه هي عادة استخدام أداة مثل valgrind أو تنقية لتحديد المشكلة.

هذه ليست إجابة على سؤالك, ، مجرد ملاحظة.

نظرا لأن بيانات الإطارات قد تكون كبيرة، لتجنب النسخ المفرط، قد يكون من الأفضل لك استخدامها

std::vector<FrameData *> frames;

تحرير: كما أشار آخرون، سيحل هذا أيضا مشكلة تحطمك.

أنت صحيحة حول push_back صنع نسخة، ولكن هل لدى Frameata منشئ نسخ مناسب ومشغل التعيين؟

أيضا، لماذا يلقي هنا:

delete[] ((uint8_t*) red[i]);

في C ++، إذا كان عليك استخدام إيصال نمط C (أو إعادة تفسير)، فإن التعليمات البرمجية مخطئ بالتأكيد تقريبا.

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