::std::equal(m.begin(), m.end(), p)
raises the following warning:
C:\Program Files\Microsoft Visual Studio 8\VC\include\xutility(2674) :
warning C4996: 'std::_Equal' was declared deprecated
C:\Program Files\Microsoft Visual Studio
8\VC\include\xutility(2661) : see declaration of 'std::_Equal'
Message: 'You have used a std:: construct that is not safe. See
documentation on how to use the Safe Standard C++ Library'
Wow. Thanks a lot. The same thing happens for a whole raft of other
standard functions, such as copy, set_difference, replace, remove,
merge, etc.
Note the interesting wording: 'std::_equal' was declared deprecated. I
was under the distinct impression that only the C++ standards committee
could deprecate anything in the std namespace...
The work-around is not pretty either. You have to basically redefine
all the affected templates:
namespace PortabilityHacks
{
template<class InputIterator1, class InputIterator2>
bool
equal(InputIterator1 first1, InputIterator1 last1, InputIterator2
first2)
{
#if _WIN32 && _MSC_VER == 1400
return ::stdext::unchecked_equal(first1, last1, first2);
#else
return ::std::copy(first1, last1, first2);
#endif
}
}
The fact that unchecked_equal() isn't documented doesn't help either.
(Although, to be fair, some of the other "deprecated" templates do have
documentation for the checked and unchecked versions in the stdext
namespace.)
Having written the workaround, I can go and add the PortabilityHacks
namespace to all points where I call one of the standard template
functions that MS have decided to deprecate. My big thanks for this
change go to the MS C++ team: you have just broken my code in many
hundreds of places :-(
I can disable the warning by setting the warning level to 4, but that
doesn't really help me. For one, I don't like to disable warnings;
certainly not with a pragma in a header file because that affects all
the customer code that includes my header file, and also not with a
compiler option. I like my code to compile clean, without warnings.
If this misfeature is the Visual C++ team's idea of standard
compliance, I'm not impressed :-(
Michi.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> certainly not with a pragma in a header file because that affects all
> the customer code that includes my header file, and also not with a
> compiler option. I like my code to compile clean, without warnings.
Push the warning level at the beginning of your header, disable the
warnings and pop the old warning state again. Then only your code will
be affected by the pragmas.
This does not make VS8 any better, but at least it is an acceptable
work-around.
hth
--
jb
(reply address in rot13, unscramble first)
I just downloaded Vis Studio Express 2005 and compiled:
#include <iostream>
#include <algorithm>
#include <deque>
#pragma warning(push, 4)
int main()
{
std::deque<int> a, b;
if (std::equal(a.begin(), a.end(), b.begin()))
std::cout << _MSC_VER << std::endl;
}
With no warnings at all...FWIW, it prints 1400.
I have to agree with MS though that the design decision behind
functions like std::equal() and std::copy() (assuming the "output"
range is are the same size as the "input" range) is questionable at
best. In fact, I would fully expect std::equal( ) to be able to take
two separate iterator ranges, and as a first check, confirm the ranges
are the same size.
std::copy()'s a little more difficult, as it could logically either a)
truncate the results if the output range was smaller or b) generate an
error (throw an exception?). I would tend to prefer a), with good
implementations supplying a run-time warning*.
Are there plans for the next C++ to have "safe" versions of these
functions?
* How many C++ libraries, especially including implementions of the std
library, have much in the way of run-time warnings? MFC does, and I've
been saved by them more than once. It's a little surprising I've never
seen a "warn_assert" type thing be proposed.
> I have to agree with MS though that the design decision behind
> functions like std::equal() and std::copy() (assuming the "output"
> range is are the same size as the "input" range) is questionable at
> best. In fact, I would fully expect std::equal( ) to be able to take
> two separate iterator ranges, and as a first check, confirm the ranges
> are the same size.
> std::copy()'s a little more difficult, as it could logically either a)
> truncate the results if the output range was smaller or b) generate an
> error (throw an exception?).
Or c) extend the ranges as needed, like an inserting iterator does.
In this case, copy is perfectly safe.
> I would tend to prefer a), with good
> implementations supplying a run-time warning*.
> Are there plans for the next C++ to have "safe" versions of these
> functions?
The current version has checked iterators turned on by default.
For any iterators returned by containers, an attempt to do an
equal comparison or a copy off the end results in a suitable
error message.
> * How many C++ libraries, especially including implementions of the std
> library, have much in the way of run-time warnings? MFC does, and I've
> been saved by them more than once. It's a little surprising I've never
> seen a "warn_assert" type thing be proposed.
Most Standard C++ libraries offer roughly the same kind of iterator
checking option I described above.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
That's true if p is a raw pointer (or otherwise an uncheckable iterator).
It's not the algorithm that generates the warning, but the use of the
algorithm with unchecked iterators -- typically raw pointers that are
unchecked and so often prone to buffer overruns.
But we need to do better, and will:
>Note the interesting wording: 'std::_equal' was declared deprecated. I
>was under the distinct impression that only the C++ standards committee
>could deprecate anything in the std namespace...
Update to the other replies: We've already agreed to change this (in
particular, the use of the word "deprecated" was not intended to mislead
but clearly is a bad choice and will be changed) and are working with
standards committee members to provide the easiest way to turn the
warnings off for specific uses, and for third-party libraries.
I'm just heading out the door, but see this other set of replies:
http://www.informit.com/discussion/index.asp?postid=21b98add-e468-4b24-b263-169a47215124#21b98add-e468-4b24-b263-169a47215124
(search for "hijack" :-) )
Herb
---
Herb Sutter (www.gotw.ca) (www.pluralsight.com/blogs/hsutter)
Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)
Are std::equal et al deprecated, or just the std::_* implementation
functions?
The design of STL emphasizes speed. The assumption behind this
"questionable" decision is that functions will be called with valid
data. The way to do this is to check for validity at the point where you
create the data. Checking every time you use it is a great recipe for
writing applications that are big and slow.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
The code that generates the warning isn't particularly intelligent. For
example, the following produces the warning, even though I can
statically prove that the code is correct:
char src[10];
char dest[20];
copy(src, src + sizeof(src) / sizeof(*src), dest);
Cheers,
Michi.
But that would limit its use to sequences where the ranges are known
in advance.
> std::copy()'s a little more difficult, as it could logically either
> a)
> truncate the results if the output range was smaller or b) generate
> an
> error (throw an exception?). I would tend to prefer a), with good
> implementations supplying a run-time warning*.
Or, c) use an insert iterator to extend the target sequence as needed.
The STL concepts are extremely general, and therefore very useful. You
should be careful not to add extra cost or limitations for its use.
Bo Persson
And how is your implementation going to handle this common case?
std::copy(a.begin(), a.end(), std::back_inserter(b))
If you need to validate the preconditions of these functions, you can do it
explicitly. There is no need (nor sometimes possibility) to burden a general
algortihm with that.
-- Gene Bushuyev
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy
True, so the single output iterator version of std::copy() is useful
for the case of the inserting interators, but otherwise, it would seem
preferable to be able to specify the output range. It's true that in
principle std::copy() is no different than, say, memcpy, which only
takes one size value, but that size isn't so obviously tied to either
the input or output range as is the case with std::copy().
> > I would tend to prefer a), with good
> > implementations supplying a run-time warning*.
> > Are there plans for the next C++ to have "safe" versions of these
> > functions?
>
> The current version has checked iterators turned on by default.
By that I assume you mean the current version of the Dinkumware
implementation of the C++ std library? I was actually referring to the
language itself - I should have been more clear.
> For any iterators returned by containers, an attempt to do an
> equal comparison or a copy off the end results in a suitable
> error message.
You mean a run-time assert?
>
> > * How many C++ libraries, especially including implementions of the std
> > library, have much in the way of run-time warnings? MFC does, and I've
> > been saved by them more than once. It's a little surprising I've never
> > seen a "warn_assert" type thing be proposed.
>
> Most Standard C++ libraries offer roughly the same kind of iterator
> checking option I described above.
>
Which I believe are mostly asserts, and hence, in most environments,
execution halting.
(I pretty much avoid standard asserts for this reason - being able to
continue execution after an assert is often a powerful debugging
technique).
I can't realistically foresee a scenario when using std::equal() that
this would not be the case (yes, in principle, you could use it with an
input iterator - the safety of which can be left to the reader's
judgement). At any rate, I'm certainly not proposing removing the
existing versions.
>
> > std::copy()'s a little more difficult, as it could logically either
> > a)
> > truncate the results if the output range was smaller or b) generate
> > an
> > error (throw an exception?). I would tend to prefer a), with good
> > implementations supplying a run-time warning*.
>
> Or, c) use an insert iterator to extend the target sequence as needed.
>
That option already exists, and I'm not suggesting any need to remove
it.
>
> The STL concepts are extremely general, and therefore very useful. You
> should be careful not to add extra cost or limitations for its use.
>
I'm not sure I see how adding safer versions of existing algorithms can
add extra cost or limitations.
> "Michi" <mi...@zeroc.com> wrote in message
> news:1132265661....@z14g2000cwz.googlegroups.com...
>
>> certainly not with a pragma in a header file because that affects all
>> the customer code that includes my header file, and also not with a
>> compiler option. I like my code to compile clean, without warnings.
>
>
> Push the warning level at the beginning of your header, disable the
> warnings and pop the old warning state again. Then only your code will
> be affected by the pragmas.
Unfortunately that doesn't quite work. Whether you get the warning
for a template is determined by its first instantiation, so popping
the warning state isn't really transparent to the rest of the code.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
> P.J. Plauger wrote:
>> <wizo...@hotmail.com> wrote in message
>> news:1132288305.1...@o13g2000cwo.googlegroups.com...
>>
>> > I have to agree with MS though that the design decision behind
>> > functions like std::equal() and std::copy() (assuming the "output"
>> > range is are the same size as the "input" range) is questionable at
>> > best. In fact, I would fully expect std::equal( ) to be able to take
>> > two separate iterator ranges, and as a first check, confirm the ranges
>> > are the same size.
>> > std::copy()'s a little more difficult, as it could logically either a)
>> > truncate the results if the output range was smaller or b) generate an
>> > error (throw an exception?).
>>
>> Or c) extend the ranges as needed, like an inserting iterator does.
>> In this case, copy is perfectly safe.
>
> True, so the single output iterator version of std::copy() is useful
> for the case of the inserting interators, but otherwise, it would seem
> preferable to be able to specify the output range.
It might seem preferable to some, but that's just one solution to
the problem, and not necessarily the best one.
> It's true that in
> principle std::copy() is no different than, say, memcpy, which only
> takes one size value, but that size isn't so obviously tied to either
> the input or output range as is the case with std::copy().
The other difference is that std::copy() is written in C++,
which has a broader spectrum of techniques it can bring to bear.
>> > I would tend to prefer a), with good
>> > implementations supplying a run-time warning*.
>> > Are there plans for the next C++ to have "safe" versions of these
>> > functions?
>>
>> The current version has checked iterators turned on by default.
>
> By that I assume you mean the current version of the Dinkumware
> implementation of the C++ std library?
Yes.
> I was actually referring to the
> language itself - I should have been more clear.
The distinction between language, library, and implementation
is fuzzier in C++.
>> For any iterators returned by containers, an attempt to do an
>> equal comparison or a copy off the end results in a suitable
>> error message.
>
> You mean a run-time assert?
That's one form, yes. Not the only form.
>> > * How many C++ libraries, especially including implementions of the std
>> > library, have much in the way of run-time warnings? MFC does, and I've
>> > been saved by them more than once. It's a little surprising I've never
>> > seen a "warn_assert" type thing be proposed.
>>
>> Most Standard C++ libraries offer roughly the same kind of iterator
>> checking option I described above.
>>
> Which I believe are mostly asserts, and hence, in most environments,
> execution halting.
> (I pretty much avoid standard asserts for this reason - being able to
> continue execution after an assert is often a powerful debugging
> technique).
Then you're in luck. IIRC, Microsoft already lets you replace at
least some of the handlers for checked iterators. The next (and
imminent) release of the Dinkumware libraries will let you replace
all of them.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
>>I have to agree with MS though that the design decision behind
>>functions like std::equal() and std::copy() (assuming the
>>"output" range is are the same size as the "input" range) is
>>questionable at best.
> The design of STL emphasizes speed. The assumption behind this
> "questionable" decision is that functions will be called with
> valid data. The way to do this is to check for validity at
> the point where you create the data.
Easier said than done in the case of std::equal. If the
iterators are only forward iterators, for example, the only way
to do so is by iterating to the end. Hardly condusive to speed.
And if the iterators are input iterators, for example if I want
to see if two files are equal, it's not even possible.
IMHO, it makes a lot of sense to support comparison of two
sequences, without necessarily knowing much about the length of
either. The result is that in practice, I rarely use
std::equal, but one of my own that does take two iterators for
both parameters.
In the case of std::copy, the issue is more complex. Comparing
two sequences of unequal length has a semantic meaning, and
makes sense; trying to do so is often reasonable, and not (or
should not be) a program error. Copying to a destination that
is too small is always an error, and it is hard to imagine what
the final destination iterator should be if the begin iterator
is a back_insertion_iterator.
> Checking every time you use it is a great recipe for writing
> applications that are big and slow.
It's also a proven recipe for writing applications which work.
And more to the point, not checking (e.g. as in gets) is a
proven recipe for applications which either don't work, or have
serious security holes. The question isn't whether you check or
not, it's who is responsible for the check.
I think you know this, and I think you're point is more that if
the check is in the client code, rather than in the library, it
can often be made statically, with no run-time cost. But not
making it statically whenever possible doesn't necessarily
result in applications that are big and slow. In the end, it's
better to let an occasional duplicate check slip in, than to
forget an essential one. The question is only one of where to
draw the line.
--
James Kanze mailto: james...@free.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
There is some macro that if defined causes the warning not to appear in this
context. Check the secure enhancements documentation.
Chris
> In the case of std::copy, the issue is more complex. Comparing
> two sequences of unequal length has a semantic meaning, and
> makes sense; trying to do so is often reasonable, and not (or
> should not be) a program error. Copying to a destination that
> is too small is always an error,
There are still occasions where I have to work with a fixed size buffer
(for whatever reason), so I process the data in chunks, or accept that
there is a risk of data truncation in some extreme cases. So the
ability to say "here's my input data and here's my output area, please
copy as much as you can" is still useful, especially if it returned an
iterator to the first non-copied element.
>
> I think you know this, and I think you're point is more that if
> the check is in the client code, rather than in the library, it
> can often be made statically, with no run-time cost.
Do you mean statically, as in determinable at compile time, or just
determinable at runtime, but based on a static size? It's hard to
imagine a case of the former, but in the latter case, a good optimizing
compiler isn't likely to produce measurably slower code between, say:
char buffer[100];
if (std::distance(my_container.begin(),
std::distance(my_container.end()) < sizeof buffer)
std::copy(my_container.begin(), my_container.end(), buffer);
and
char buffer[100];
std::safe_copy(my_container.begin(), my_container.end(), buffer, buffer
+ sizeof buffer);
Where safe_copy checks that the output range is big enough first.
However, if the output iterators are non-random-access iterators with
an O(n) std::distance(), and you happen to know the size in advance,
*and* performance is measurably affected, there is an argument for
using a non-checking version of std::copy().
> Pete Becker wrote:
>
>
>>Checking every time you use it is a great recipe for writing
>>applications that are big and slow.
>
>
> It's also a proven recipe for writing applications which work.
> And more to the point, not checking (e.g. as in gets) is a
> proven recipe for applications which either don't work, or have
> serious security holes.
I must have missed it; I didn't see anyone in this thread urging no
checking. I did object to the naive assertion that the library should
always make this sort of check.
> The question isn't whether you check or
> not, it's who is responsible for the check.
Yup. The assumption behind MS's warnings is that the library should make
all the checks. That's not the design policy behind STL.
>
> I think you know this, and I think you're point is more that if
> the check is in the client code, rather than in the library, it
> can often be made statically, with no run-time cost. But not
> making it statically whenever possible doesn't necessarily
> result in applications that are big and slow. In the end, it's
> better to let an occasional duplicate check slip in, than to
> forget an essential one. The question is only one of where to
> draw the line.
>
My point is that it is not inherently bad to use functions that don't
check their input. Giving warnings for such calls enforces bad design
policies. There's far too much use of the buzzword "security" in place
of actual thought and understanding.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
> > > I have to agree with MS though that the design decision
> > > behind functions like std::equal() and std::copy()
> > > (assuming the "output" range is are the same size as the
> > > "input" range) is questionable at best. In fact, I would
> > > fully expect std::equal( ) to be able to take two separate
> > > iterator ranges, and as a first check, confirm the ranges
> > > are the same size.
> > But that would limit its use to sequences where the ranges
> > are known in advance.
> I can't realistically foresee a scenario when using
> std::equal() that this would not be the case (yes, in
> principle, you could use it with an input iterator - the
> safety of which can be left to the reader's judgement). At
> any rate, I'm certainly not proposing removing the existing
> versions.
What's wrong with something like:
if ( std::equal( std::istreambuf_iterator( file1 ),
std::istreambuf_iterator(),
std::istreambuf_iterator( file1 ) ) ) {
// ...
}
except that it doesn't work with the current definition of
std::equal. Logically, I would expect equal to take two fully
defined sequences (i.e. two pairs of iterators). If the
iterators are of type random_access_iterator, then it could
actually skip all of the conversions if the distances weren't
the same. Otherwise, it checks both pairs each time through the
loop. If it gets to the end of one sequence, and the other
sequence is not at the end, it returns false.
Of course, I'm basing my opinion here on the name of the
function. If it were called isprefix, or something, one might
reason differently (although there would still be some argument
for having both iterators for both sequences).
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> > In the case of std::copy, the issue is more complex.
> > Comparing two sequences of unequal length has a semantic
> > meaning, and makes sense; trying to do so is often
> > reasonable, and not (or should not be) a program error.
> > Copying to a destination that is too small is always an
> > error,
> There are still occasions where I have to work with a fixed
> size buffer (for whatever reason), so I process the data in
> chunks, or accept that there is a risk of data truncation in
> some extreme cases. So the ability to say "here's my input
> data and here's my output area, please copy as much as you
> can" is still useful, especially if it returned an iterator to
> the first non-copied element.
Useful in some cases, perhaps, but that's a different function.
> > I think you know this, and I think you're point is more that
> > if the check is in the client code, rather than in the
> > library, it can often be made statically, with no run-time
> > cost.
> Do you mean statically, as in determinable at compile time, or
> just determinable at runtime, but based on a static size?
Statically, as in determinable without executing the code.
Compile time in a very extended sense, e.g. in a code review, or
something like that. The point is that if it is provable (not
necessarily to the compiler) that the destination is large
enough, then the "checks" in correct code take zero time, *if*
they are done at the client level. The client proves that the
call is safe, and simply doesn't code them as C++ code.
(There is, of course, the question of what "sufficiently large"
means. For example, back_insertion_iterator can fail with
bad_alloc, and an ostream_iterator can fail if the disk is full.
Both of these examples, however, do give a means to the client
of detecting the error.)
[...]
> However, if the output iterators are non-random-access
> iterators with an O(n) std::distance(), and you happen to know
> the size in advance, *and* performance is measurably affected,
> there is an argument for using a non-checking version of
> std::copy().
In practice, most of my invocations of std::copy use either a
back_insertion_iterator or an ostream_iterator as the
destination. Which means that I don't check anything myself
before hand, and I count on the iterator access mechanism to
create the proper error (setting badbit in the stream, or
throwing bad_alloc). Note that the authors of the standard did
think of this issue; ostreambuf_iterator has a special function,
failed(), which must be tested after the copy.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34