2014-10-04 60 views
0

我有一個Vector類可以返回它自己的片。這些切片將引用實際的矢量,因此切片和原點都將被修改。一個問題是以下codesnippet:當對象超出範圍/得到無效時收到通知

class VectorBase { 
    // Offers basic methods 
} 

class Vector : VectorBase { 
    // An actual vector 
} 

class VectorRef : VectorBase { 
    // References parts of another vector 
    // Constructor creates a slice of the base vector 
    VectorRef(VectorBase base, int start, int end); 
} 

void foo() { 
    Vector* a = new Vector(); 
    VectorRef b(*a, 1,4); 
    delete a; 
    b.length(); // <---- Problem because a isn't valid anymore 
} 

我想簡單地通過當用戶調用切片對象的方法拋出異常來解決這個是這樣的。我如何確定原始對象是否超出範圍?

+5

不要返回引用局部變量是什麼。在那裏,完成。 – CoryKramer 2014-10-04 15:16:53

+3

*「因爲超出範圍而出現問題」*說,'b'本身怎麼樣? :)你正在返回一個對一個不存在的對象的引用。 – jrok 2014-10-04 15:17:53

+0

哦,是的,你是對的......你們誰能想到一個'a'會得到oos但是'b'沒有的情況嗎?因爲這個問題不是關於這個特例,而是更多的關於一般的「a是無效的,如何通過b注意到?」編輯完成該問題。 – WorldSEnder 2014-10-04 15:28:48

回答

2

有幾種解決方法。

如果您有權訪問c++11boost一種方法是使用共享和弱指針。這將迫使你將你的Vector實例化爲共享指針,但是你不必實現你自己的引用方案。這也意味着VectorRef不擁有Vector。

class VectorRef : VectorBase { 
    // References parts of another vector 
    // Constructor creates a slice of the base vector 
    VectorRef(std::shared_ptr<VectorBase> base, int start, int end) : 
     m_base(base), m_start(start), m_end(end) 
    { 
    } 

    std::weak_ptr<VectorBase> m_base; 

    length() override 
    { 
     if (auto base = m_base.lock()) { // Has to be copied into a shared_ptr before usage 
     { 
     return m_end-m_start; 
     } 
     else 
     { 
     trow(VectorException("Base has expired")); 
     } 
    } 
} 

void foo() { 
    std::shared_ptr<Vector> a = std::make_shared<Vector>(); 
    VectorRef b(a, 1,4); 
    a.reset(); 
    b.length(); // Will throw an exception 
} 
+0

是否有你能想到的地方發生的一切「引擎蓋下」(不在方法'foo')的方法嗎?這是API的一部分,如果沒有'foo'中的'shared_ptr',它會看起來更乾淨。 – WorldSEnder 2014-10-04 16:36:08

+0

看到@sjdowling答案更含蓄的版本,基本上分配矢量的私人數據和共享與參考,通過weak_ptr的可能會更你在找什麼。更好的解決方案將取決於您的實際實施情況 – 2014-10-05 13:23:13

0

正如已經評論的那樣,問題出現了,因爲引用所引用的對象被破壞了。這也是爲什麼你應該只返回局部變量作爲副本而不是指針/引用。如果你真的想知道一個物體是否超出範圍,你可以使用嘈雜的析構函數。

~Vector() { std::cout << "Noisy Destructor, reports when an object is destroyed."; } 

但是這並不能解決問題,因爲對象仍然超出範圍。我想你以後想用它來工作。所以你有一些選擇來解決你的問題。

  1. 您可以返回對象的副本。
  2. 您可以動態分配對象並返回引用。

現在回到原來的問題。如果您通常想知道指針是否無效,請確保將其設置爲零,以便您隨時可以檢查if(Pointer == NULL)//if out of scope。除此之外,我不知道任何有效的方法來確定引用是否無效。除此之外,作爲程序員你有責任確保程序不訪問內存,不允許訪問。

+0

一個很好的答案,如果我是唯一一個使用Vector但不夠好的,因爲它是數學API的一部分,所以我必須使__sure__不被使用。 – WorldSEnder 2014-10-04 16:09:15

+0

好的,我明白了......我很抱歉,我無法給你一個明確的答案。你可以考慮的其他選項...使用指針編寫自己的引用類,並在調用析構函數時始終將其設置爲0 ...或使用std :: shared_ptr,這可能會有所幫助。我從來沒有用過它,並且沒有經驗。看看http://www.cplusplus.com/reference/memory/shared_ptr – Koto 2014-10-04 16:23:01

1

哈拉爾的答案可能是你想要往下走的方向,但我想問一下VectorVectorBase內存管理幾個問題。它看起來像是按照值將VectorBase傳遞給VectorRef構造函數,然後期望它創建的引用在之後仍然有效,您是否真的想要這樣做?這意味着VectorBase的複製構造函數共享其資源的所有權,除非您正在執行一些複雜的寫入複製內容(或者即使您是這樣),但這可能是一件壞事。此外爲什麼它甚至採取VectorBase而不是VectorVectorBase是否意味着是一個接口?在這種情況下,你肯定應該傳入對該構造函數的引用。

你似乎什麼想可能是沿着線的東西:

template <class T> class Vector { 
    std::shared_ptr<std::vector<T>> m_stuff; 
    ... 
} 

template < class T> VectorRef { 
    std::weak_ptr<std::vector<T>> m_ref; 
    VectorRef(const Vector<T>& v, size_t begin, size_t end); 
    ... 
} 

再檢查std::weak_ptr每個用法哈拉爾建議。然而我也會考慮有VectorRef也有std::shared_ptr除非完全違背商業邏輯,片可以延長概念數組的壽命,並肯定會導致更多的優雅失敗不是拋出異常的發生。

另一件事我會考慮的是,你提到這意味着是一個數學API在這種情況下,我建議拋出這整個事情窗外的一部分。我期望數學庫專注於性能,引用計數智能指針的開銷簡直是不可接受的。您應該專注於在接口文檔中明確說明什麼是API的安全用法,以及如何引用陣列片在陣列生命週期之外無效並將正確的內存管理責任移動到用戶上。這是完全可以接受的,並且是標準庫確實相對於迭代器等

相關問題