سؤال

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

#include <iostream>
#include <list>

#define NUM_VERTICES 8

using namespace std;

enum { WHITE, GRAY, BLACK };

struct vertex
{
    int color;
    int distance;
    char parent;
};

int main()
{
    //create the vertices
    vertex r = {WHITE, NULL, NULL};

    //create pointer to the vertex structures
    vertex *pr = &r;

    //create a list to hold the vertices
    list<vertex*> *r_list = new list<vertex*>;

    list<vertex*>::iterator it;

    r_list->insert(it, pr);
}
هل كانت مفيدة؟

المحلول

هناك العديد من الأشياء الخاطئة هنا.

أولا قبالة، أنت لا تهيمن للمقتطف، مثل البعض الآخر قد قال:

list<vertex*>::iterator it = r_list->begin();

القيام بذلك وسوف يكون الكود الخاص بك على ما يرام. لكن الرمز الخاص بك يتم بطريقة سيئة.

لماذا تخصص القائمة من كومة؟ انظر إلى التعليمات البرمجية الخاصة بك: لديك تسرب الذاكرة. أنت لا تتصل delete r_list في أى مكان. هذا هو السبب في أنه يجب عليك استخدام المؤشرات الذكية (std::unique_ptr, std::shared_ptr إذا كان لديك C ++ 11، بزيادة معادلات خلاف ذلك: boost::scoped_ptr و boost::shared_ptr)

ولكن الأفضل من ذلك، فقط افعل ذلك على المكدس:

//create a list to hold the vertices
list<vertex*> r_list;

list<vertex*>::iterator it = r_list->begin();

r_list.insert(it, pr);

بالإضافة إلى ذلك، فإن استخدام جهاز الكمبيوتر لإدراجه هو الذهاب إلى الأمور الشاقة الطويلة. مجرد استخدام دفع الجبهة () أو إدفع إلى الخلف():

//create a list to hold the vertices
list<vertex*> r_list;

r_list.push_back(pr);

شيء آخر: إذا عثرت قائمتك على قمة الرأس التي قمت بإنشائها، فستشير إلى شيء غير صالح.

علي سبيل المثال:

// global
list<vertex*> r_list;

void some_function(void)
{
    //create the vertices
    vertex r = {WHITE, NULL, NULL};

    //create pointer to the vertex structures
    vertex *pr = &r;

    r_list.push_back(pr);
} // right here, vertex r stops existing: the list now contains an
  // invalid pointer.

أحد الحلول هو تخزين المؤشرات إلى القمم المخصصة لكومة:

// global
list<vertex*> r_list;

void some_function(void)
{
    //create the vertices
    vertex *r = new vertex;
    r->color = WHITE;
    r->distance = 0;
    r->parent = 0;

    r_list.push_back(r);
}

الآن حتى بعد الوظيفة تشير القائمة إلى قمة مخصصة بكرامة صالحة. هذا الآن لديه مشكلة أنه عند الانتهاء من استخدام القائمة، تحتاج إلى الذهاب من خلال LSIT والاتصال delete في كل عنصر. هذه المشكلة ساعدت باستخدام مكتبة حاويات المؤشر.

أفضل طريقة، على الرغم من تخزين القمم فقط (بدلا من المؤشرات إليها):

//create a list to hold the vertices
list<vertex> r_list;

//create the vertices
vertex r = {WHITE, NULL, NULL};

r_list.push_back(r);

إذا أعطيت قمة رأس المنشئ، فيمكنك حتى إنشاءها في مكانها:

struct vertex
{
    int color;
    int distance;
    char parent;

    vertex(int _color, int _distance, char _parent) :
    color(_color),
    distance(_distance),
    parent(_parent)
    {
    }
};

//create a list to hold the vertices
list<vertex> r_list;

r_list.push_back(vertex(WHITE, NULL, NULL));

(هذه الآن خارج مشكلتك)

أولا، يتم استخدام NULL بشكل عام فقط عند التعامل مع المؤشرات. حيث distance و parent ليست مؤشرات، واستخدام 0 لتهيئة لهم، بدلا من NULL:

//create the vertices
vertex r = {WHITE, 0, 0};

ثانيا، استخدم constants بدلا من #define:

#define NUM_VERTICES 8 // <- bad
const int NumberVertices = 8; // <- good

أخيرا، قم بإعطاء Enum اسم، أو ضعه في مساحة الاسم:

enum Color { WHITE, GRAY, BLACK };

نأمل هذه المساعدة!

نصائح أخرى

أنت لم تهتم بالماء، لذلك فهي غير صالحة لإدراجها. يمكنك استخدام r_list->push_back(pr) بدلا من ذلك، على سبيل المثال.

أيضا، لن تكون المؤشرات في قائمتك صالحة بمجرد الخروج من النطاق. من الواضح أن هذه ليست مشكلة في هذه الحالة منذ ذلك main(), ، لكنني أفترض أن هذا ليس هو المثال الدقيق حيث ستستخدم الرمز، لذلك قد يعود لدغة لك ...

بادئ ذي بدء، أنت غير تهيئة it إلى أي شيء. هل تعني:

list<vertex*>::iterator it = r_list->begin();

أيضا، لماذا تقوم بتهيئة int و char إلى null؟ عادة ما يستخدم الناس null for المؤشرات.

أيضا، ماذا عن تسمية تعينك والاستفادة من سلامة النوع من النوع، بدلا من استخدامها كأحدث؟

أيضا، لا حاجة لإنشاء متغير جديد لإنشاء مؤشر إلى Vertex. عند استدعاء إدراج، يمكنك تمرير &r.

أيضا، كما يشير بيتر، لماذا لا تستخدم فقط push_back()?

يجب أن تبدو الكود الخاص بك أكثر مثل هذا:


using namespace std;

enum Color { 
    WHITE, 
    GRAY, 
    BLACK 
};

struct vertex
{
    Color color;
    int distance;
    char parent;
};

int main(int argc, char** argv) {
    //create the vertices
    vertex r = {WHITE, 0, ''};

    //create a list to hold the vertices
    list* r_list = new list();

    list::iterator it = r_list->begin();
    r_list->insert(it, &r);

    // Or even better, use push_back (or front)
    r_list->push_back(&r);
}

لم تتم تهيئة it, ، لذلك أنت تدرج في مكان / مؤشر عشوائي / غير مهم.

طرق طبيعية لإضافة عناصر إلى std::list تشمل طرقها push_back و push_front; ؛ كنت تستخدم عادة insert فقط إذا كنت قد حددت سابقا المكان المحدد الذي تريد إدراج عنصر آخر إضافي.

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