Reputation: 22074
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.
Upvotes: 1
Views: 1394
Reputation: 9991
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
Upvotes: 1
Reputation: 6436
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.
Upvotes: 1