2015-10-22 4 views
1

У меня есть указатель на некоторые данные, которые я хочу поместить в строку. Я думал, что использование std::copy должно быть самым безопасным подходом.Указатели для вставки в итератор для копирования в контейнер STL

Однако в Visual Studio 2010 я получаю предупреждение

предупреждение C4996: «станд :: _ Copy_impl»: Вызов функции с параметрами, которые могут быть небезопасны - это вызов зависит от вызывающего абонента, чтобы проверить, что прошло значения верны. Чтобы отключить это предупреждение, используйте -D_SCL_SECURE_NO_WARNINGS.

И, конечно, предупреждение правильное. Есть некоторые checked_array_iterator объекты, описанные на MSDN 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 

Кстати, вы должны использовать static_cast вместо reinterpret_cast при преобразовании из void* в T*.

Вообще:

Если есть портативный стандартный способ, я бы скорее хотел бы использовать это вместо reyling на расширение MS.

Это один из самых предупреждений annyoing в Visual Studio 2015. В то время как его сообщение является правда, это должно быть очевидно для всех, кто использует 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

Смежные вопросы