Here's a simplified version of the code I'm using:
namespace BasketNovel {
void Engine::BuryEntities()
{
std::list<Entity*>::iterator iter = p_entities.begin();
while (iter != p_entities.end())
{
if ( (*iter)->getAlive() == false )
{
delete (*iter);
iter = p_entities.erase( iter ); //.erase returns next element
}
else iter++;
}
}
}
I'm getting the following warning from Intel Static Analysis:
BasketNovel.cpp(567): warning #12221: slicing of object "iter" passed as actual argument 2 in call to "std::_List_iterator > > std::list >::erase(std::_List_const_iterator > >)" occurs due to implicit type conversion
I believe that this is basically saying that I'm causing an implicit type conversion in:
iter = p_entities.erase( iter );
(note: I get the same warning even if I change my code to: p_entities.erase( iter++ ); )
I don't quite understand what I'm "slicing" in the above.
What exactly does this mean and how I should go about solving this warning? I'd rather slightly convoluted code than turning off warning messages completely.
What is Object Slicing
Object Slicing is the fact of copying/moving only part of an object, this occurs in general with Base/Derived couples:
struct Base { int i; };
struct Derived: Base { int j; };
void slice() {
Derived d = {};
Base b(d); // b is a "sliced" version of `d`
}
and can lead to nastiness.
Here though, this is just a false positive...
Can it be easier ?
Yes, certainly.
// Place to be deleted values at the end
auto const it = std::partition(p_entities.begin(), p_entities.end(),
[](Entity const* e) { return not e or not e->getAlive(); });
// Delete them
std::for_each(it, p_entities.end(), [](Entity const* e) { delete e; });
// Remove them
p_entities.erase(it, p_entities.end());
It looks like your std::list::erase() method is expecting a std::list<Entity*>::const_iterator and you are passing it an std::list<Entity*>::iterator. This could mean you are compiling the code with C++11 support.
One solution would be to perform the removals in two steps. First, use std::for_each to delete and set to 0 pointers to objects that are not alive.
#include <algorithm>
void deleteDead(Entity* e) {
if (e->getAlive()) return;
delete e;
e = 0;
}
std::for_each(p_entities.begin(), p_entities.end(), deleteDead);
Second, use the [erase-remove idiom](erase-remove idiom to remove elements that are 0.
#include <algorithm>
p_entities.erase(std::remove(p_entities.begin(), p_entities.end(), 0),
p_entities.end() );
After about a month of doing other work, I've realised the answer to the problem was basically in changing
std::list::iterator
to
std::list::const_iterator
The slicing was occurring because .erase() required a const_iterator and made the implicit conversion from iterator.
I'd recommend typedef ing std::list in the header to cover possible future type changes.
I'm keeping MatthieuM.'s answer up though because I think the definition on Object Slicing is far more useful than this answer itself.
Related
So I've solved this problem, but I need your opinion if what I did is best practice.
A simple class holds a vector of unique_ptrs to order objects. I will explain the member variable null_unique below.
class order_collection {
typedef std::unique_ptr<order> ord_ptr;
typedef std::vector<ord_ptr> ord_ptr_vec;
ord_ptr_vec orders;
ord_ptr null_unique;
public:
...
const ord_ptr & find_order(std::string);
....
So I need the users of this class to get access to the order unique_ptr if found. However I'm not going to move the object out of the vector so I'm returning the unique_ptr as const ref. My implementation of the find_order method:
const order_collection::ord_ptr & order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return null_unique; // can't return nullptr here
return *it;
}
Since I'm returning by reference I can't return a nullptr. If I try to do so, I get warning : returning reference to a temporary. And if nothing is found the program crashes. So I added a unique_ptr<order> member variable called null_unique and I return it when find doesn't find an order. This solves the problem and warning is gone and doesn't crash when no order is found.
However I'm doubting my solution as it make my class ugly. Is this the best practice for handling this situation?
You should only return and accept smart pointers when you care about their ownership semantics. If you only care about what they're pointing to, you should instead return a reference or a raw pointer.
Since you're returning a dummy null_unique, it is clear that the caller of the method doesn't care about the ownership semantics. You can also have a null state: you should therefore return a raw pointer:
order* order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return nullptr;
return it->get();
}
It doesn't really make sense to return a unique_ptr here, reference or otherwise. A unique_ptr implies ownership over the object, and those aren't really the semantics being conveyed by this code.
As suggested in the comments, simply returning a raw pointer is fine here, provided that your Project Design explicitly prohibits you or anyone on your team from calling delete or delete[] outside the context of the destructor of a Resource-owning object.
Alternatively, if you either have access to Boost or C++17, a std::optional<std::reference_wrapper<order>> might be the ideal solution.
std::optional<std::reference_wrapper<order>> order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return {}; //empty optional object
return **it; //will implicitly convert to the correct object type.
}
/*...*/
void func() {
auto opt = collection.find_order("blah blah blah");
if(!opt) return;
order & ord = opt->get();
/*Do whatever*/
}
(EDIT: In testing on the most recent version of MSVC 2017, it looks like std::reference_wrapper<T> will happily do an implicit conversion to T& if you tell it to. So replacing opt->get() with *opt should work exactly the same.)
As long as I'm here, I might point out that a std::vector<std::unique_ptr<type>> object has a very "Code Smell" sense to it. std::vector<type> implies ownership of the object as is, so unless you have a good reason to prefer this (maybe the objects are large, unmovable/uncopyable, and you need to insert and remove entries frequently? Maybe this is a polymorphic type?), you're probably better off reducing this to a simple std::vector.
EDIT:
The boost version is subtly different, because boost::optional has no restrictions against "optional references", which are specifically forbidden by the C++ Standard Library's version of std::optional. The boost version is actually going to be slightly simpler:
//return type changes, nothing else changes
boost::optional<order&> order_collection::find_order(std::string id) {
auto it = std::find_if(orders.begin(),orders.end(),
[&](const order_collection::ord_ptr & sptr) {
return sptr->getId() == id;
});
if (it == orders.end())
return {}; //empty optional object
return **it; //will implicitly convert to the correct object type.
}
/*...*/
//Instead of calling opt->get(), we use *opt instead.
void func() {
auto opt = collection.find_order("blah blah blah");
if(!opt) return;
order & ord = *opt;
/*Do whatever*/
}
Let's say I have this:
struct HoldStuff {
std::vector<StuffItem> items;
std::set<StuffItem, StuffItemComparator> sorted_items;
}
Now, during a refactor, I may have stuff in items or I may have it in sorted_items, but regardless I want to do the same thing with each item. I want to do something like this:
HoldStuff holder; // assume it was filled earlier
auto iter = holder.items.empty() ? holder.sorted_items.begin() :
holder.items.begin();
auto iter_end = holder.items.empty() ? holder.sorted_items.end() :
holder.items.end();
for (; iter != iter_end; ++iter) {
auto& item = *iter;
// Do stuff
}
When I go to compile this, I get errors complaining about incompatible operand types. Surely this is possible, no?
You have two options:
use type-erasure to get a runtime polymorphism on the iterator (any_range or any_iterator)
delegate do_stuff to a function template that takes any kind of iterator
Here is an illustration with code:
#include <vector>
#include <set>
#include <iostream>
#include <boost/range/any_range.hpp>
template<typename Iterator>
void do_stuff(Iterator begin, Iterator end) {}
int main()
{
std::vector<int> items;
std::set<int> sorted_items;
// first option
typedef boost::any_range<int, boost::forward_traversal_tag, int&, std::ptrdiff_t> my_any_range;
my_any_range r;
if(items.empty())
r = my_any_range(sorted_items);
else
r = my_any_range(items);
for (auto& x : r) {
std::cout << x << " ";
}
// second option
// this could also be a lambda and std::for_each
if(items.empty())
do_stuff(sorted_items.begin(), sorted_items.end());
else
do_stuff(items.begin(), items.end());
return 0;
}
Both sides of the ternary operator need to have the same type. In your case, they are different - std::vector<>::iterator and std::set<> iterator. A suitable solution seems to be some sort of a an iterator wrapper, which returns one or another depending on the initial condition.
The errors are correct: auto keyword works during compilation. In an easy way, it just deduces the type of assignment and uses this real type. But decision if it's vector's iterator or set's is made in runtime. So type can not be deduced.
As SergeyA said, I'm wrong here, compiler fail on ?: operator, before auto. But the reason is still the same - it has no idea which type to use for the result.
You should probably use some more generic iterator type + polymorphism, or you can make this function parameterized on type , where T is an iterator type. I would prefer to do it this way:
template<class T> do_stuff(T &c) { for (auto &el : c) { /*Whatever*/ } }
...
if (!items.empty()) {
do_stuff(items);
} else if (!sorted_items.empty()) {
do_stuff(sorted_items);
}
P.S.: It's a conception, I didn't test the code.
auto means the compiler will deduce the type of what follows, at compilation time.
The return type of the ternary conditional operator in this case is what follows the question mark, so it is std::set<StuffItem, StuffItemComparator>::iterator and the compiler tries to cast what follows the column (std::vector<StuffItem>::iterator) to this incompatible type, hence the compiler error.
What you can do is make your item processing code generic, like so:
auto doStuff = [] (StuffItem& item) {
// do stuff with item...
};
if( holder.items.size() )
for_each( holder.items.begin(), holder.items.end(), doStuff );
else if( holder.sorted_items.size() )
for_each( holder.sorted_items.begin(), holder.sorted_items.end(), doStuff );
The following code seems to always follow the true branch.
#include <map>
#include <iostream>
class TestClass {
// implementation
}
int main() {
std::map<int, TestClass*> TestMap;
if (TestMap[203] == nullptr) {
std::cout << "true";
} else {
std::cout << "false";
}
return 0;
}
Is it defined behaviour for an uninitialized pointer to point at nullptr, or an artifact of my compiler?
If not, how can I ensure portability of the following code? Currently, I'm using similar logic to return the correct singleton instance for a log file:
#include <string>
#include <map>
class Log {
public:
static Log* get_instance(std::string path);
protected:
Log(std::string path) : path(path), log(path) {};
std::string path;
std::ostream log;
private:
static std::map<std::string, Log*> instances;
};
std::map<std::string, Log*> Log::instances = std::map<std::string, Log*>();
Log* Log::get_instance(std::string path) {
if (instances[path] == nullptr) {
instances[path] = new Log(path);
}
return instances[path];
}
One solution would be to use something similar to this where you use a special function provide a default value when checking a map. However, my understanding is that this would cause the complexity of the lookup to be O(n) instead of O(1). This isn't too much of an issue in my scenario (there would only ever be a handful of logs), but a better solution would be somehow to force pointers of type Log* to reference nullptr by default thus making the lookup check O(1) and portable at the same time. Is this possible and if so, how would I do it?
The map always value-initializes its members (in situations where they are not copy-initialized, of course), and value-initialization for builtin types means zero-initialization, therefore it is indeed defined behaviour. This is especially true for the value part of new keys generated when accessing elements with operator[] which didn't exist before calling that.
Note however that an uninizialized pointer is not necessarily a null pointer; indeed, just reading its value already invokes undefined behaviour (and might case a segmentation fault on certain platforms under certain circumstances). The point is that pointers in maps are not uninitialized. So if you write for example
void foo()
{
TestClass* p;
// ...
}
p will not be initialized to nullptr.
Note however that you might want to check for presence instead, to avoid accumulating unnecessary entries. You'd check for presence using the find member function:
map<int, TestClass*>::iterator it = TestMap.find(203);
if (it == map.end())
{
// there's no such element in the map
}
else
{
TestClass* p = it->second;
// ...
}
Yes, that's defined behaviour. If an element isn't yet in a map when you access it via operator[], it gets default constructed.
In dynamically typed languages like JavaScript or PHP, I often do functions such as:
function getSomething(name) {
if (content_[name]) return content_[name];
return null; // doesn't exist
}
I return an object if it exists or null if not.
What would be the equivalent in C++ using references? Is there any recommended pattern in general? I saw some frameworks having an isNull() method for this purpose:
SomeResource SomeClass::getSomething(std::string name) {
if (content_.find(name) != content_.end()) return content_[name];
SomeResource output; // Create a "null" resource
return output;
}
Then the caller would check the resource that way:
SomeResource r = obj.getSomething("something");
if (!r.isNull()) {
// OK
} else {
// NOT OK
}
However, having to implement this kind of magic method for each class seems heavy. Also it doesn't seem obvious when the internal state of the object should be set from "null" to "not null".
Is there any alternative to this pattern? I already know it can be done using pointers, but I am wondering how/if it can be done with references. Or should I give up on returning "null" objects in C++ and use some C++-specific pattern? Any suggestion on the proper way to do that would be appreciated.
You cannot do this during references, as they should never be NULL. There are basically three options, one using a pointer, the others using value semantics.
With a pointer (note: this requires that the resource doesn't get destructed while the caller has a pointer to it; also make sure the caller knows it doesn't need to delete the object):
SomeResource* SomeClass::getSomething(std::string name) {
std::map<std::string, SomeResource>::iterator it = content_.find(name);
if (it != content_.end())
return &(*it);
return NULL;
}
Using std::pair with a bool to indicate if the item is valid or not (note: requires that SomeResource has an appropriate default constructor and is not expensive to construct):
std::pair<SomeResource, bool> SomeClass::getSomething(std::string name) {
std::map<std::string, SomeResource>::iterator it = content_.find(name);
if (it != content_.end())
return std::make_pair(*it, true);
return std::make_pair(SomeResource(), false);
}
Using boost::optional:
boost::optional<SomeResource> SomeClass::getSomething(std::string name) {
std::map<std::string, SomeResource>::iterator it = content_.find(name);
if (it != content_.end())
return *it;
return boost::optional<SomeResource>();
}
If you want value semantics and have the ability to use Boost, I'd recommend option three. The primary advantage of boost::optional over std::pair is that an unitialized boost::optional value doesn't construct the type its encapsulating. This means it works for types that have no default constructor and saves time/memory for types with a non-trivial default constructor.
I also modified your example so you're not searching the map twice (by reusing the iterator).
Why "besides using pointers"? Using pointers is the way you do it in C++. Unless you define some "optional" type which has something like the isNull() function you mentioned. (or use an existing one, like boost::optional)
References are designed, and guaranteed, to never be null. Asking "so how do I make them null" is nonsensical. You use pointers when you need a "nullable reference".
One nice and relatively non-intrusive approach, which avoids the problem if implementing special methods for all types, is that used with boost.optional. It is essentially a template wrapper which allows you to check whether the value held is "valid" or not.
BTW I think this is well explained in the docs, but beware of boost::optional of bool, this is a construction which is hard to interpret.
Edit: The question asks about "NULL reference", but the code snippet has a function that returns by value. If that function indeed returned a reference:
const someResource& getSomething(const std::string& name) const ; // and possibly non-const version
then the function would only make sense if the someResource being referred to had a lifetime at least as long as that of the object returning the reference (otherwise you woul dhave a dangling reference). In this case, it seems perfectly fine to return a pointer:
const someResource* getSomething(const std::string& name) const; // and possibly non-const version
but you have to make it absolutely clear that the caller does not take ownership of the pointer and should not attempt to delete it.
I can think of a few ways to handle this:
As others suggested, use boost::optional
Make the object have a state that indicates it is not valid (Yuk!)
Use pointer instead of reference
Have a special instance of the class that is the null object
Throw an exception to indicate failure (not always applicable)
unlike Java and C# in C++ reference object can't be null.
so I would advice 2 methods I use in this case.
1 - instead of reference use a type which have a null such as std::shared_ptr
2 - get the reference as a out-parameter and return Boolean for success.
bool SomeClass::getSomething(std::string name, SomeResource& outParam) {
if (content_.find(name) != content_.end())
{
outParam = content_[name];
return true;
}
return false;
}
This code below demonstrates how to return "invalid" references; it is just a different way of using pointers (the conventional method).
Not recommended that you use this in code that will be used by others, since the expectation is that functions that return references always return valid references.
#include <iostream>
#include <cstddef>
#define Nothing(Type) *(Type*)nullptr
//#define Nothing(Type) *(Type*)0
struct A { int i; };
struct B
{
A a[5];
B() { for (int i=0;i<5;i++) a[i].i=i+1; }
A& GetA(int n)
{
if ((n>=0)&&(n<5)) return a[n];
else return Nothing(A);
}
};
int main()
{
B b;
for (int i=3;i<7;i++)
{
A &ra=b.GetA(i);
if (!&ra) std::cout << i << ": ra=nothing\n";
else std::cout << i << ": ra=" << ra.i << "\n";
}
return 0;
}
The macro Nothing(Type) returns a value, in this case that represented by nullptr - you can as well use 0, to which the reference's address is set. This address can now be checked as-if you have been using pointers.
From C++17 on, you can use the native std::optional (here) in the following way:
std::optional<SomeResource> SomeClass::getSomething(std::string name) {
if (content_.find(name) != content_.end()) return content_[name];
return std::nullopt;
}
Here are a couple of ideas:
Alternative 1:
class Nullable
{
private:
bool m_bIsNull;
protected:
Nullable(bool bIsNull) : m_bIsNull(bIsNull) {}
void setNull(bool bIsNull) { m_bIsNull = bIsNull; }
public:
bool isNull();
};
class SomeResource : public Nullable
{
public:
SomeResource() : Nullable(true) {}
SomeResource(...) : Nullable(false) { ... }
...
};
Alternative 2:
template<class T>
struct Nullable<T>
{
Nullable(const T& value_) : value(value_), isNull(false) {}
Nullable() : isNull(true) {}
T value;
bool isNull;
};
Yet another option - one that I have used from time to time for when you don't really want a "null" object returned but instead an "empty/invalid" object will do:
// List of things
std::vector<some_struct> list_of_things;
// An emtpy / invalid instance of some_struct
some_struct empty_struct{"invalid"};
const some_struct &get_thing(int index)
{
// If the index is valid then return the ref to the item index'ed
if (index <= list_of_things.size())
{
return list_of_things[index];
}
// Index is out of range, return a reference to the invalid/empty instance
return empty_struct; // doesn't exist
}
Its quite simple and (depending on what you are doing with it at the other end) can avoid the need to do null pointer checks on the other side. For example if you are generating some lists of thing, e.g:
for (const auto &sub_item : get_thing(2).sub_list())
{
// If the returned item from get_thing is the empty one then the sub list will
// be empty - no need to bother with nullptr checks etc... (in this case)
}
This question raised after reading this tutorial:
http://www.cprogramming.com/tutorial/auto_ptr.html
There you can find the following statement: A subtle consequence of this behavior is that auto_ ptrs don't work well in all scenarios. For instance, using auto _ptr objects with the standard template library can lead to problems as some functions in the STL may make copies of the objects in containers such as the vector container class. One example is the sort function, which makes copies of some of the objects in the container being sorted. As a consequence, this copy can blithely delete the data in the container!
Most of the papers concerning 'auto_ptr' tell us something like following:
"Never use 'auto_ptr' with STL containers! They often copy their elements while performing intrinsic operations. For example consider sort on std::vector".
So my goal is to write the code sample that illustrates this point or prove that such examples are only theoretically true and weird on practice.
P.S. #everybody_who_also_knows_that_auto_ptr_is_deprecated
I also know this. But don't you consider technical reasons (legacy code or old compiler) that may not allow new pointer containers usage? And moreover this question is about old and bad (if you'd like) auto_ptr.
I don't have MSVC right now, but judging from the error from g++, I guess this is the reason:
auto_ptr<T> only has a "copy constructor" which takes mutable references (§D.10.1.1[auto.ptr.cons]/2–6):
auto_ptr(auto_ptr& a) throw();
template<class Y> auto_ptr(auto_ptr<Y>& a) throw();
But vector::push_back will accept a const reference (§23.3.6.1[vector.overview]/2).
void push_back(const T& x);
So it is impossible to construct an auto_ptr via push_back because no constructor takes a const reference.
From what you write, it seems that you already know everything that there is to know about containers of auto_ptrs and why they are unsafe.
Therefore, I assume that your interest in containers of auto_ptrs is purely teaching oriented. I understand your frustration in attempting to build a deliberate counter-example: in fact, most implementers of standard containers have put in place work-arounds to avoid accidentally triggering the broken semantics of auto_ptrs.
So, here's an example that I have written myself precisely for teaching:
class MyClass {
int a;
public:
MyClass (int i) : a(i) { }
int get() const { return a; }
};
int main() {
constexpr unsigned size = 10;
std::vector< std::auto_ptr<MyClass> > coap;
coap.resize(size);
for (unsigned u=0; u<size; u++)
coap[u] = std::auto_ptr<MyClass>( new MyClass( rand() % 50 ));
std::sort( coap.begin(), coap.end(),
[]( std::auto_ptr<MyClass> a,
std::auto_ptr<MyClass> b) { return a->get() < b->get(); });
}
Compiling it with g++ 4.9.2 will lead to an executable that will segfault nicely.
You can rewrite the example above even more concisely by using type deduction:
std::sort( coap.begin(), coap.end(),
[]( auto a, auto b) { return a->get() < b->get(); });
Note that the problem is not in the specific implementation of std::sort, which seems to be auto_ptr-safe. It is rather in the comparison lambda function I am passing to std::sort, that deliberately accepts its arguments by value, thus destroying the objects in the container every time a comparison is performed.
If you changed the lambda so that it receives its arguments by reference, as shown below, most STL implementations would actually behave correctly, even if you are doing something that is conceptually wrong.
std::sort( coap.begin(), coap.end(),
[]( const std::auto_ptr<MyClass> & a,
const std::auto_ptr<MyClass> & b) { return a->get() < b->get(); });
Good luck!
STEP 1
Lets' solve this problem in a straight way:
#include <iostream>
#include <vector>
#include <algorithm>
template<> struct std::less<std::auto_ptr<int>>: public std::binary_function<std::auto_ptr<int>, std::auto_ptr<int>, bool> {
bool operator()(const std::auto_ptr<int>& _Left, const std::auto_ptr<int>& _Right) const
{ // apply operator< to operands
return *_Left < *_Right;
}
};
int wmain() {
using namespace std;
auto_ptr<int> apai(new int(1)), apai2(new int(2)), apai3(new int(3));
vector<auto_ptr<int>> vec;
vec.push_back(apai3);
vec.push_back(apai);
vec.push_back(apai2);
for ( vector<auto_ptr<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << i->get() << L'\t';
vector<int> vec2;
vec2.push_back(3);
vec2.push_back(2);
vec2.push_back(5);
sort(vec2.begin(), vec2.end(), less<int>());
sort(vec.begin(), vec.end(), less<auto_ptr<int>>());
return 0;
}
On MSVCPP11 the error text is following:
_Error 1 error C2558: class 'std::auto_ptr<Ty>': no copy constructor available or copy constructor is declared 'explicit' c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0 608
The conclusion is: I even cannot compile such example. Why do they prevent me to do something that I cannot compile?? Their preventions are not always true.
STEP 2
We cannot use auto_ptr as vector element type directly due to auto_ptr design. But we can wrap `auto_ptr' in the way presented below.
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <functional>
template<typename T> class auto_ptr_my: public std::auto_ptr<T> {
public:
explicit auto_ptr_my(T *ptr = 0) {
this->reset(ptr);
}
auto_ptr_my<T> &operator=(const auto_ptr_my<T> &right) {
*(static_cast<std::auto_ptr<T> *>(this)) = *(static_cast<std::auto_ptr<T> *>(const_cast<auto_ptr_my *>(&right)));
return *this;
}
auto_ptr_my(const auto_ptr_my<T>& right) {
*this = right;
}
};
namespace std
{
template<> struct less<auto_ptr_my<int> >: public std::binary_function<auto_ptr_my<int>, auto_ptr_my<int>, bool> {
bool operator()(const auto_ptr_my<int>& _Left, const auto_ptr_my<int>& _Right) const
{ // apply operator< to operands
return *_Left < *_Right;
}
};
}
int wmain() {
using namespace std;
auto_ptr_my<int> apai(new int(1)), apai2(new int(2)), apai3(new int(3));
vector<auto_ptr_my<int>> vec;
vec.push_back(apai3);
vec.push_back(apai);
vec.push_back(apai2);
for ( vector<auto_ptr_my<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << **i << L'\t';
sort(vec.begin(), vec.end(), less<auto_ptr_my<int>>());
for ( vector<auto_ptr_my<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << **i << L'\t';
return 0;
}
This code works well showing that auto_ptr can be used with vector and sort with no memory leaks and crashes.
STEP 3
As KennyTM posted below:
add this code before return 0; statement:
std::vector<auto_ptr_my<int>> vec2 = vec;
for ( vector<auto_ptr_my<int>>::const_iterator i(vec2.cbegin()) ; i != vec2.cend() ; ++i )
wcout << **i << L'\t';
wcout << std::endl;
for ( vector<auto_ptr_my<int>>::const_iterator i(vec.cbegin()) ; i != vec.cend() ; ++i )
wcout << **i << L'\t';
wcout << std::endl;
...and get memory leaks!
CONCLUSION
Sometimes we can use auto_ptr with containers without visible crash, sometimes not. Anyway it is bad practice.
But don't forget that auto_ptr is designed in such way that you cannot use it straight with STL containers and algorithms: against you have to write some wrapper code. At last using auto_ptr with STL containers is for your own risk. For example, some implementations of sort will not lead to the crash while processing vector elements, but other implementations will lead directly to the crash.
This question has academic purposes.
Thanks to KennyTM for providing STEP 3 crash example!
The conclusion is: I even cannot compile such example. Why do they prevent me to do something that I cannot compile??
IIRC, it is the other way around: the compiler vendor takes steps to prevent you from compiling something that you shouldn't be able to do. The way the standard is written, they could implement the library in a way that the code compiles, and then fails to work properly. They can also implement it this way, which is seen as superior because it's one of those few times where the compiler is actually allowed to prevent you from doing something stupid :)
The right answer is "never use auto_ptr at all" -- its deprecated and never became part of the standard at all, for precisely the reasons outlined here. Use std::unique_ptr instead.