Storing a raw pointer is perfectly fine, if
a. the object holding the raw pointer does not participate in the management of the life-time of the pointed object
b. and the life-time of the pointed object extends beyond the time that the (raw) pointer is held.
For instance, the typical (simple, elegant and efficient) implementation of
std::istream_iterator<> holds a raw pointer the stream object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
/// Provides input iterator semantics for streams.
template<typename _Tp, typename _CharT = char,
typename _Traits = char_traits<_CharT>, typename _Dist = ptrdiff_t>
class istream_iterator
: public iterator<input_iterator_tag, _Tp, _Dist, const _Tp*, const _Tp&>
{
public:
typedef _CharT char_type;
typedef _Traits traits_type;
typedef basic_istream<_CharT, _Traits> istream_type;
private:
istream_type* _M_stream;
// ...
|
1.
std::istream_iterator<> does not manage the life-time of the stream.
2. the life-time of the stream extends beyond the time of the iterator used to iterate through the stream.
3. in the end-of-stream iterator, the pointer is a nullptr (there is no stream object).
https://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01524_source.html
For a discussion about the preposterous proposition: 'You don't really need raw pointers since C++11', see:
http://www.cplusplus.com/forum/beginner/166841/
This is absolutely fine:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
struct A { /* ... */ };
struct B
{
B() = default ; // initialise ptr to nullptr
B( A& object ) : ptr( std::addressof(object) ) {}
void set_A() { ptr = nullptr ; }
void set_A( A& object ) { ptr = std::addressof(object) ; }
// there may be no object of type A; in this case ptr would be null
// ptr is a 'non-owning' pointer,
// B does not participate in the management of the life-time of the pointed object
// the life-time of the pointed object extends beyond the time that B holds a pointer to it
A* ptr = nullptr ;
};
struct C
{
C() = default ; // initialise ptr to nullptr
C( const A& object ) : ptr( std::addressof(object) ) {}
void set_A() { ptr = nullptr ; }
void set_A( const A& object ) { ptr = std::addressof(object) ; }
// ptr is a 'non-owning' pointer,
// there may be no object of type A; in this case ptr would be null
// B does not manage the life-time of the pointed object
// the life-time of the pointed object extends beyond the life-time of B
const A* ptr = nullptr ;
};
|