2011-11-21 48 views
2

當我有一個初始化的迭代器分配一個unintialized問題。以下代碼片段在使用Visual Studio 2010構建時會產生訪問衝突。在以前版本的Visual Studio中,代碼應該可以工作。訪問衝突分配未初始化的迭代器

#include <list> 

int main() { 
    std::list<int> list; 
    std::list<int>::iterator it = list.begin(); 
    std::list<int>::iterator jt; 
    it = jt; // crashes in VS 2010 
} 

這不會被認爲是有效的C++嗎?

我需要這個代碼來實現「光標」類,要麼無處點或列表中的某個特定元素。如果我沒有對容器的引用,還有什麼可以用作未初始化迭代器的值?

+0

我不明白你要做什麼。你初始化'it'指向一個有效的東西,然後你立即用一個未定義的值覆蓋它? –

+0

您的評論與您的​​代碼不匹配:您是否打算輸入jt = it;而不是在你的代碼?如果是這樣,那應該很好。 – kfmfe04

+0

你不能使用'jt'做任何事情。你甚至不能交換這個東西:'std :: swap(it,jt)'將在VS2010上產生相同的錯誤。 – MSalters

回答

6
it = jt; // crashes in VS 2010 

這會調用未定義的行爲(UB)。根據C++標準,jt是不與任何容器相關聯的奇異迭代,最表達式的結果是不確定的奇異迭代器。

從C++標準(2003)的部分§24.1/ 5讀取(參見粗體文本特異性),

正如常規指針數組 保證有一個指針 值指向過去陣列的最後一個元素 ,因此對於任何迭代器類型 有指向 過去 相應容器的最後一個元素的迭代值。這些值 被稱爲過去的最終值。值的迭代器I的量, 表達式* i定義被稱爲 提領的 。該庫從不 假定過去的最終值是 可解引用。 迭代也可以 具有不與任何容器相關聯 奇異值。 [實施例:(與INT * X)的 未初始化的指針x的聲明之後,x必須總是被假設爲具有 的指針的奇異值]大多數表達式的 結果是 未定義奇異值; 唯一的例外是將 非奇異值賦值給迭代器,該迭代器保存奇異值。在這種情況下, 奇異值將覆蓋 與任何其他值相同的方式。 可解引用值始終爲 非奇異值。

如果MSVS2010崩潰,這是UB的無限可能性之一,因爲UB意味着任何事情都可能發生;該標準沒有規定任何行爲。

+2

爲什麼'jt'未初始化?它不是基本的數據類型,但有一個被調用的構造函數。 – fschoenm

+0

@fschoenm:現在查看我的答案。現在它更完整。 – Nawaz

-1

list.end()指向容器外的任何地方,所以我們可以認爲它像指向無處。 也訪問單位變量會導致未定義的行爲。

+0

它是默認初始化的,不是未初始化的。而'list.end()'指向一個特定的列表,這意味着當列表被銷燬時迭代器失效。 – MSalters

2

C++ 11,24.2。1/3:

大多數表達式的結果對於奇異值是未定義的; 唯一的例外是破壞一個迭代器,該迭代器包含一個單獨的值,一個非奇異值賦值給一個迭代器,該迭代器保存奇異值,並且對於滿足DefaultConstructible需求的迭代器,使用一個值初始化的迭代器作爲複製或移動操作的來源,爲 。

該列表是限制性的,您的示例未在允許的例外中列出。 jt是單數且默認初始化的。因此它可能不會被用作複製操作的來源。

0

您需要一個KNOWN值才能使用信號。除非你有一個容器來獲取.end(),否則你認爲這是你的問題。

你真正需要做的是遠離思考,你可以使用'特殊'迭代器值來處理不涉及容器的古怪案件。迭代器雖然像指針一樣工作,但不是指針。他們沒有相當於'NULL'。

取而代之,使用布爾標誌值來查看容器是否已設置,並確保迭代器(如果有多個迭代器(如果有多個迭代器的話)都會在容器已知時設置爲某個有效值,並且當您丟失容器時,標誌會被設置爲false。然後你可以在任何迭代器操作之前檢查標誌。

+0

是的,我完成了。在我的情況下,問題出現在默認賦值運算符中。 – fschoenm