简体   繁体   中英

Wrapping pointers into an iterator for copying into an STL container

I have a pointer to some data which I want to put into a string. I thought that using std::copy should be the safest approach.

However, in Visual Studio 2010 I get a warning

warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS.

And of course the warning is correct. There are some checked_array_iterator objects described on MSDN checked_array_iterator which can be used to wrap up a pointer like this and make it compatible with STL iterators.

The problem is, that this checked_array_iterator can only be used as a target, but not as the source.

So when I try to use it like this, the application crashes or doesn't compile:

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

If there is a portable standard way, I would rather like to use this instead of reyling on an MS extension.

In your specific case, you can use a std::string constructor or assign() method, see cppreference .

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

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

By the way, you should use static_cast instead of reinterpret_cast when converting from void* to T* .

Generally:

If there is a portable standard way, I would rather like to use this instead of reyling on an MS extension.

This is one of the most annyoing warnings in Visual Studio 2015. While its message is true, it should be obvious to everyone that uses std::copy() on raw pointers. The proposed workaround with checked_array_iterator does not only completely over-engineer a simple problem, but it also introduces non-standard classes and thus makes your code non-portable.

If I were you, I would define _SCL_SECURE_NO_WARNINGS and make perfectly valid C++ code compile again without warnings.

Pointers are perfectly fine (random-access)-iterators. The problem lies in you copying data into bad memory. p->begin() which is equal to s.begin() which is equal to s.end() points to invalid memory. To fix this you can use for example

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

or alternatively

#include <iterator>

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

or maybe simply

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM