2016-02-11 30 views
0

我在托管C++中只有初学者问题,这让我头疼。我正在创建一个元素列表,一个指针应该显示这个列表的当前元素。初始化一个静态指针导致<未定义的值>

问题是,当我将第一个元素分配给此列表时,我想用我的指针引用此列表的开头(“varPointer = & firstElem”)。但在此之后,指针根本没有任何价值。

这里是我的代码的简化版本:

ref class ElementClass 
{ 
public: 
    value struct Element 
    { 
     //some items here ...; 
     Element *Next, *Previous; 
    }; 
    ... 
} 

ref class Queue 
{ 
public: 
     static Element* queue; 

     static void AddElem(Element* elem) { 
     //Check, if queue is empty 
     if (queue == nullptr) { 
      queue = elem; 
      queue->Previous = nullptr; 
     } 
     else {    
      queue->Next = elem; 
      elem->Previous = queue; 
      queue = elem;   
     } 
    } 
} 

该计划不会引发任何错误,并在下一次迭代名单似乎仍然是空的。 即使我使用“静态元素*队列= 0”或队列指针始终具有的东西来显式初始化队列。与“元素”的一个实例,初始化是不可能的(“类型‘interior_ptr’的值不能被用于初始化类型的实体‘元素*’)在此,我加入:

... 
public: 
    static Element^ tmpElem = gcnew Element(); 
    static Element* queue = &tmpElem; 
... 

程序从未使用其他语句。 我明白任何形式的帮助,谢谢大家提前。

(我熟悉一般的编程,但我新的C++的方式。)

+0

*但我是新来的C++ * - 我是这个“托管C++”的新手。你发布的肯定不是C++,至少是ANSI C++。 – PaulMcKenzie

+0

'元素*接下来,*上一个;'具有非托管的指向可能被分配管理的数据的指针。小心混合托管指针和非托管指针。赔率是货物,这是编译器警告的。 – user4581301

+0

in'void AddElem(Element elem)''elem'通过值传递。这会导致'elem'作为传入的临时副本,在退出函数时会被销毁。 'queue = &elem;'存储一个指向这个临时副本的指针,并在函数结束并且'elem'被销毁后指向无效内存。这里是龙。 – user4581301

回答

0

好吧。这是教育

因此,如果y OU与传统的非托管指针

Element *Next = nullptr, *Previous = nullptr; 

去,然后由值

static void AddElem(ElementClass::Element elem) { 
    //Check, if queue is empty 
    if (queue == nullptr) { 
     queue = &elem; 
     queue->Previous = nullptr; 
    } 
    else { 
     queue->Next = &elem; 
     elem.Previous = queue; 
     queue = &elem; 
    } 
} 

Kablooey使用通! elem被拷贝进去,并且将在退出的时候被销毁,或者在不久的将来会在某个时刻被标记为销毁并被垃圾收集器杀死。我不确定这件事,但它会被破坏,很可能在你做完之前。这留下了一堆指向无效内存的指针。如果程序没有崩溃,那不是因为它工作。这是因为你不走运,而且看起来很有效。

如果你走一路回C-风格:

Element *Next = nullptr, *Previous = nullptr; 

,然后通过在非托管指针

static void AddElem(ElementClass::Element * elem) { 
    //Check, if queue is empty 
    if (queue == nullptr) { 
     queue = elem; 
     queue->Previous = nullptr; 
    } 
    else { 
     queue->Next = elem; 
     elem->Previous = queue; 
     queue = elem; 
    } 
} 

它的工作原理,但你必须做所有的内存管理用手。没有垃圾收集。

如果您使用托管指针,您将获得托管内存。好东西。

Element ^Next = nullptr, ^Previous = nullptr; 

然后

static void AddElem(ElementClass::Element elem) { 
    //Check, if queue is empty 
    if (queue == nullptr) { 
     queue = elem; 
     queue->Previous = nullptr; 
    } 
    else { 
     queue->Next = elem; 
     elem.Previous = queue; 
     queue = elem; 
    } 
} 

此店,而且据我所知,管理ELEM的副本,保持副本活着。原始元素不受影响。它不知道它是相连的,因为它不是。副本被链接。这可能是你所需要的。视为Element是一种值类型,这应该是你想要的。

否则进行端到端托管指针。

static void AddElem(ElementClass::Element^elem) { 
    //Check, if queue is empty 
    if (queue == nullptr) { 
     queue = elem; 
     queue->Previous = nullptr; 
    } 
    else { 
     queue->Next = elem; 
     elem->Previous = queue; 
     queue = elem; 
    } 
} 

注意我没有更改任何链接列表逻辑。这工作得很好。

+0

值类型('value struct')的工作方式与C++类类似,因为它们是按值传递的。 GC不需要涉及本地值类型变量。清理值类型的唯一时间是当它们是引用类型('ref class')的一部分时,它自己被收集。这包括盒装值。值类型只是引用类型内存的一部分,因此会一路清除。 C++/CLI(* not * managed C++ - 这是一个遗产)是一种特殊的野兽:你得到C++ *的复杂性和CLR的复杂性,*和*你需要将两者混合在一起。 –

+0

就是这样。我将Element的所有实例从值类型或非托管指针'*'更改为托管指针'^',就像您建议的那样。现在它工作正常。显然我误解了托管指针... 感谢大家的帮助,特别是@ user4581301,他显然有一个漫长的夜间研究。 – Bluesky787