2015-10-22 32 views
1

我有一個指向我想要放入字符串的某些數據的指針。我認爲使用std::copy應該是最安全的方法。將指針包裝成迭代器以便複製到STL容器

然而,在Visual Studio 2010中,我得到一個警告

警告C4996:「的std :: _ Copy_impl」:與可能不安全的參數函數調用 - 此調用依賴於調用方檢查通過值是正確的。要禁用此警告,請使用-D_SCL_SECURE_NO_WARNINGS。

當然,警告是正確的。在MSDN checked_array_iterator上描述的一些checked_array_iterator對象可以用來包裝一個像這樣的指針,並使它與STL迭代器兼容。

問題是,這checked_array_iterator只能用作目標,但不能作爲源。

所以,當我嘗試使用它像這樣,應用程序崩潰或無法編譯:

char buffer[10] = "Test"; 
std::string s; 

// These are parameters from an external call and only shown here to illustrate the usage. 
char *pTargetAdress = &s; 
const char *oBegin = buffer; 
const char *oEnd = oBegin+sizeof(buffer); 

std::string *p = reinterpret_cast<std::string *>(pTargetAdress); 
std::copy(oBegin, oEnd, p->begin()); // crash 

stdext::checked_array_iterator<const char *>beg(oBegin, oEnd-oBegin); 
stdext::checked_array_iterator<const char *>end(oEnd, 0); 
std::copy(beg, end, p->begin()); // crash 

stdext::checked_array_iterator<const char *>v(oBegin, oEnd-oBegin); 
std::copy(v.begin(), v.end(), p->begin()); // doesn't compile 

如果有一種便攜式標準的方式,我寧願喜歡上的,而不是使用reyling這MS擴展。

+0

一定有一'字符串:: assign',可以把你的緩衝區作爲參數,帶或不帶緩衝區大小。 –

+0

@BoPersson,是的,你是對的。這是我現在使用的。 – Devolus

回答

1

指針是完美的(隨機訪問)引發器。問題在於你將數據拷貝到壞的內存中。 p->begin()等於s.begin()等於s.end()指向無效內存。爲了解決這個問題,你可以使用例如

std::string *p = reinterpret_cast<std::string *>(pTargetAdress); 
p->resize(oEnd - oBegin); //resize to make room for the data 
std::copy(oBegin, oEnd, p->begin()); // no more crash 

或可替代

#include <iterator> 

std::string *p = reinterpret_cast<std::string *>(pTargetAdress); 
std::copy(oBegin, oEnd, std::back_inserter(*p)); // copy by appending to the end 

或者也許只是

std::string *p = reinterpret_cast<std::string *>(pTargetAdress); 
*p = std::string(oBegin, oEnd); // copy by temporary 
+0

我以爲副本,會創建所需的空間,所以我沒有使用調整大小。謝謝! – Devolus

+0

我最終使用了'assign'作爲評論建議的內容,但是這個答案也有效,並且符合我想要的精神,因爲我不想爲複製創建中間字符串。 – Devolus

1

在您的具體情況下,您可以使用std::string構造函數或assign()方法,請參見cppreference

const char* pointer = ...; 
std::size_t size = ...; 

std::string string(pointer, size); 
std::string string(pointer); // if null-terminated 

順便說一句,你應該從void*轉換爲T*時使用static_cast,而不是reinterpret_cast

一般:

如果有一種便攜式標準的方式,我寧願喜歡用這個來代替reyling上的MS擴展。

這是在Visual Studio 2015年最annyoing警告之一,而它的消息真實的,它應該是有目共睹的,關於原始指針使用std::copy()。與checked_array_iterator建議的解決方法不僅完全過度設計一個簡單的問題,但它也引入了非標準類,從而使您的代碼不可移植。

如果我是你的話,我會定義_SCL_SECURE_NO_WARNINGS並且在沒有警告的情況下再次編譯完全有效的C++代碼。

+0

在原始代碼中它是一個(char *),所以我必須使用reinterpret。將其轉換爲帖子中的示例時出現錯誤。 – Devolus

+0

添加const修飾符不需要轉換,特別是不需要'reinterpret_cast'。你究竟做了什麼,你得到了什麼錯誤? – TheOperator

+0

char * pTargetAdress; static_cast (pTargetAdress); => char *不能通過靜態轉換轉換爲std :: string *。我的意思是在翻譯過程中在示例中使用void指針是我的一個錯誤。我糾正了這個問題以反映這一點。 – Devolus