2014-07-15 32 views
0

執行此代碼時出現段錯誤。特別是在調用g_lru_stack.add_node(& lru_node)之後。extern全局對象似乎沒有初始化其成員

在GDB下運行表明虛擬節點看起來不像它已被初始化。這與外部全局初始化有關嗎?如果是這樣,任何幫助將不勝感激。

我已經包含來自頭文件和cpp文件的片段。

具體來說,我的問題是這樣的: 如何獲得LRU_Stack g_lru_stack,在object.cc的頂部聲明,以調用不帶參數的LRU_Node ctor。

看來這個ctor永遠不會被調用,所以爲什麼我的虛擬節點沒有被初始化。

Object.h

class obj_payload; 
extern cas_mutex g_lru_stack_mutex; 


class LRU_Node { 

private: 
     obj_payload* payload; 
    LRU_Node* up; 
    LRU_Node* down; 
    size_t predicted_bytes_in_cache; 

public: 
    LRU_Node() : payload(nullptr), up(this), down(this), predicted_bytes_in_cache(1337) {}  // Dummy ctor 

    LRU_Node(obj_payload* p) : payload(p), up(nullptr), down(nullptr), predicted_bytes_in_cache(88) {} // Normal Creation of node 

    //Adds a node to the top of the stack 
    //Has dummy context 
    void add_to_stack(LRU_Node* newNode); 

    //Sets how many bytes of the object are predicted to be in the cache 
    //Has dummy context 
    void is_node_in_cache(LRU_Node* node); 

    //Moves a node to the top of the stack 
    //Has dummy context 
    void move_node_to_top(LRU_Node* node); 

    //Has context of caller 
    size_t get_predicted_bytes_in_cache(); 
}; 

class LRU_Stack { 
    LRU_Node dummy; 

public: 
void add_node(LRU_Node* node); 

void move_node_to_top(LRU_Node* node); 
}; 
extern LRU_Stack g_lru_stack; 



class obj_payload { 
    typedef uint32_t ctr_t; 
private: 
    ctr_t refcnt; 
    const uint32_t sz;    // size of the data space in bytes 
    LRU_Node lru_node;    // Jordan -- This arg objects node for the LRU_Stack 


    obj_payload(typeinfo tinfo_, 
     uint32_t size_, 
     int refcnt_init=1) 
    : refcnt(refcnt_init), 
     sz(size_), 
     tinfo(tinfo_), lru_node(this) { 

     g_lru_stack.add_node(&lru_node);  


    } 

Object.cc

#include "object.h" 

namespace obj { 

//Jordan -- Global LRU_Node Stack 
cas_mutex g_lru_stack_mutex; 
LRU_Stack g_lru_stack; 

//Adds a node to the top of the stack 
//Has dummy context 
void LRU_Node::add_to_stack(LRU_Node* newNode) { 
     newNode->down = down;   // Set the new nodes previous -> dummys previous 
     newNode->up = this;   // Set new nodes next -> dummy 
     down->up = newNode;   // Dummy next -> new node (i.e. Previous top of stack node up -> newNode) 
     down = newNode;    // Dummy previous -> new node (i.e. Dummy down pointer now links back round to the new node at the top) 
} 

//Sets how many bytes of the object are predicted to be in the cache 
//Has dummy context 
void LRU_Node::is_node_in_cache(LRU_Node* node) { 
     size_t total = 0; 
     LRU_Node* orignal = node; 

     while (node != this) { 
       total += node->payload->get_size(); // Add current size to total 
       node = node->up;      // Go to next node 
     } 
     node = orignal; //Reset node to the passed in node, then set how many bytes it has contained within cache 

     if (total <= cache_size) { 
       node->predicted_bytes_in_cache = node->payload->get_size(); 
     } 
     else { 
       node->predicted_bytes_in_cache = (node->payload->get_size()) - (total - cache_size) < node->payload->get_size() ? (node->payload->get_size()) - (total - cache_size) : 0; 
     } 
} 

//Moves a node to the top of the stack 
//Has dummy context 
void LRU_Node::move_node_to_top(LRU_Node* node) { 

     if (down != node) { // Check that the node to move is not already top of stack 
       node->down->up = node->up; 
       node->up->down = node->down; 

       if (down == node->up) { // If the node is seccond top of stack 
         node->up->up = node; 
       } 

       node->down = down; 
       node->up = this; 
       down->up = node; 
       down = node; 
     } 
} 

//Has context of caller 
size_t LRU_Node::get_predicted_bytes_in_cache() { 
     return predicted_bytes_in_cache; 
} 

//Has dummy context 
bool LRU_Node::is_empty() { 
     return (up == this); 
} 

void LRU_Stack::add_node(LRU_Node* node) { 
    g_lru_stack_mutex.lock(); 
    dummy.add_to_stack(node); 
    g_lru_stack_mutex.unlock(); 
} 

void LRU_Stack::move_node_to_top(LRU_Node* node) { 
    g_lru_stack_mutex.lock(); 
    dummy.is_node_in_cache(node); 
    dummy.move_node_to_top(node); 
    g_lru_stack_mutex.unlock(); 
} 

回答

2

「外部全局」 都沒有對象(除非它們包含一個初始值):他們是前瞻性聲明。

全局對象的初始化分爲兩個階段:

  • 所有這些與編譯時間常數初始化完成後,剩下的就是零。
  • 運行時初始化器按對象定義的順序運行。 (對不同編譯單元中的對象沒有排序保證!)。

似乎UB讓你那裏。

爲了解決錯誤,執行下列操作之一:

  • 把對象的定義在相同的編譯單元(最有效的方法)其第一次使用之前。
  • 將對象作爲靜態存放在存取函數中。 Init將首先使用(線程安全!)。

    Type& getTypeSingleton() { 
        static Type x/*optional initializer*/; 
        return x; 
    } 
    
  • (實施相關的)上的命令行第一提到的編譯單元將首先在所有當前的實現被初始化(如effifient爲第一,但脆弱)。
+0

而當您在頭文件中定義全局extern變量時,應該將文件範圍非extern聲明放在一個常規源文件中。如果你願意,你可以附加一個初始化程序。 –

+0

那麼我該如何去獲取LRU_Stack g_lru_stack對象來調用它的成員變量上的ctor? 我確定我在這裏做了非常愚蠢的事情。 – Jordan

+0

您能否介紹一下accessor函數的方法? – Jordan