C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

shared_ptr and nullptr
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
Joe Gottman
Guest





PostPosted: Tue Nov 14, 2006 5:09 am    Post subject: shared_ptr and nullptr Reply with quote



If the nullptr proposal
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1601.pdf) is
accepted into the standard, then shared_ptr will need to be modified to work
with it. nullptr is a special value (of type nullptr_t) that can be
converted to a null pointer of any pointer or pointer-to-member type but not
to any integral or boolean type. It is meant as a replacement for the NULL
macro.

It seems likely that code, especially in templates, might want to
initialize a shared_ptr<X> with nullptr. Unfortunately, as shared_ptr is
now written this will fail because the relevant constructor for
shared_ptr<X> looks like
template<class Y> shared_ptr(Y *p);

Since nullptr can be converted to any pointer type, there's no best match.
The obvious solution is to give shared_ptr a new constructor
shared_ptr(nullptr_t);
so that we can construct a shared_ptr from nullptr. Naturally we would need
to define shared_ptr::reset(nullptr_t) as well.

The things I am not sure about are
1) Does this constructor produce an empty shared_ptr (i.e. one that is
equivalent to a default-constructed shared_ptr) or a shared_ptr that owns a
null pointer (i.e. one that is equivalent to shared_ptr(static_cast<X
*>(0)) )?The major difference between these 2 cases is that the first one
cannot throw and does not carry use-count information while the second one
can throw and does carry use-count information.
2) Should this constructor be explicit? If not, we would probably want
to define operator== and operator!= that take a shared_ptr and a nullptr_t.
3) Would we want to have a constructor that takes a nullptr_t and a
destructor object? I'm not sure what use one of these would be, except
maybe to simulate a Java finally block and run code when we leave a scope
for any reason.

Joe Gottman

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Tue Nov 14, 2006 7:19 am    Post subject: Re: shared_ptr and nullptr Reply with quote



Joe Gottman wrote:
Quote:
If the nullptr proposal
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1601.pdf) is
accepted into the standard, then shared_ptr will need to be modified to work
with it. nullptr is a special value (of type nullptr_t) that can be
converted to a null pointer of any pointer or pointer-to-member type but not
to any integral or boolean type. It is meant as a replacement for the NULL
macro.

It seems likely that code, especially in templates, might want to
initialize a shared_ptr<X> with nullptr. Unfortunately, as shared_ptr is
now written this will fail because the relevant constructor for
shared_ptr<X> looks like
template<class Y> shared_ptr(Y *p);

Since nullptr can be converted to any pointer type, there's no best match.

As a consequence of wording on page 9 of N1601, the nullptr_t is
defined as if the following two definitions exist:

typedef most_derived_t* nullptr_t;
typedef most_base_t::* nullptr_t;

Thus there is no ambiguity with the shared_ptr constructor

template<class Y> shared_ptr(Y *p);

because it is matched as if Y is the most_derived_t type.


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Peter Dimov
Guest





PostPosted: Tue Nov 14, 2006 3:40 pm    Post subject: Re: shared_ptr and nullptr Reply with quote



Joe Gottman wrote:

Quote:
The things I am not sure about are
1) Does this constructor produce an empty shared_ptr (i.e. one that is
equivalent to a default-constructed shared_ptr) or a shared_ptr that owns a
null pointer (i.e. one that is equivalent to shared_ptr(static_cast<X
*>(0)) )?The major difference between these 2 cases is that the first one
cannot throw and does not carry use-count information while the second one
can throw and does carry use-count information.

This would depend on the semantics of nullptr, in particular, whether
Y* is deducible from it, and with what Y. If it isn't, empty is the
only reasonable option. If it is, my vote still goes for empty.

Quote:
2) Should this constructor be explicit? If not, we would probably want
to define operator== and operator!= that take a shared_ptr and a nullptr_t.

If it constructs an empty shared_ptr, it should be implicit. Users want
this:

void f( shared_ptr<X> px );

int main()
{
f( nullptr );
}

to work.

Quote:
3) Would we want to have a constructor that takes a nullptr_t and a
destructor object? I'm not sure what use one of these would be, except
maybe to simulate a Java finally block and run code when we leave a scope
for any reason.

No, I don't think that we want it (but we might have it anyway, in
which case we probably don't want to prohibit it, either).

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Tue Nov 14, 2006 8:50 pm    Post subject: Re: shared_ptr and nullptr Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
Andrei Polushin ha scritto:
As a consequence of wording on page 9 of N1601, the nullptr_t is
defined as if the following two definitions exist:

typedef most_derived_t* nullptr_t;
typedef most_base_t::* nullptr_t;

Thus there is no ambiguity with the shared_ptr constructor

template<class Y> shared_ptr(Y *p);

because it is matched as if Y is the most_derived_t type.

I'm sorry, but I don't see anything on page 9 of N1601 that could lead
to that interpretation. Could you please elaborate?

N1601 defines on page 9 that "nullptr_t is both
a _pointer_type_ and
a _pointer_to_member_type_".

A _pointer_ type is defined in [C++98, 8.3.1/1] (reworded by me):

In a declaration

T1 * D1

the type of D1 is "pointer to T1."

A _pointer_to_member_ type is defined in [C++98, 8.3.3/1] (reworded):

In a declaration

T2 :: * D2

the type of D2 is "pointer to member of type T."

Both types were defined in terms of declarations. Then if nullptr_t
is a combination of both types, it is defined in terms of both
declarations:

T1 * D1
T2 :: * D2

N1601 may have another intent, that was not expressed in the proposed
wording. But look at at use cases at page 7:

// Specialization cases
//
template<typename T> void g( T t );
g( 0 ); // specializes g, T = int
g( nullptr ); // specializes g, T = nullptr_t
g( (float*) nullptr ); // specializes g, T = float*

// Partial specialization cases
//
template<typename T> class X { };
template<typename T> class X<T*> X { };
template<typename T> class X<T::*> X { };
X<nullptr_t> x; // error, ambiguous; nullptr_t is both a pointer
// and pointer-to-member type, so it.s undecidable
// which partial specialization to use

The last case is "ambiguous", and on page 5 they say that

nullptr_t matches both a T* and a T::* partial specialization.
If it matches two partial specializations of the same template,
the result is ambiguous because neither partial specialization
is more specialized than the other.

Thus the following is unambiguous:

template<typename T> class X { };
template<typename T> class X<T*> X { };
X<nullptr_t> x;

I don't see how it differs from the OP question about shared_ptr.
If there is no ambiguity with X, there should be no ambiguity with
shared_ptr too.


Quote:
What are most_derived_t and most_base_t?

They are my names for T1 and T2.


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Tue Nov 14, 2006 11:32 pm    Post subject: Re: shared_ptr and nullptr Reply with quote

Andrei Polushin ha scritto:
Quote:

As a consequence of wording on page 9 of N1601, the nullptr_t is
defined as if the following two definitions exist:

typedef most_derived_t* nullptr_t;
typedef most_base_t::* nullptr_t;

Thus there is no ambiguity with the shared_ptr constructor

template<class Y> shared_ptr(Y *p);

because it is matched as if Y is the most_derived_t type.



I'm sorry, but I don't see anything on page 9 of N1601 that could lead
to that interpretation. Could you please elaborate? What are
most_derived_t and most_base_t?

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Wed Nov 15, 2006 1:20 am    Post subject: Re: shared_ptr and nullptr Reply with quote

Peter Dimov ha scritto:
Quote:
Joe Gottman wrote:

The things I am not sure about are
1) Does this constructor produce an empty shared_ptr (i.e. one that is
equivalent to a default-constructed shared_ptr) or a shared_ptr that owns a
null pointer (i.e. one that is equivalent to shared_ptr(static_cast<X
*>(0)) )?The major difference between these 2 cases is that the first one
cannot throw and does not carry use-count information while the second one
can throw and does carry use-count information.

This would depend on the semantics of nullptr, in particular, whether
Y* is deducible from it, and with what Y. If it isn't, empty is the
only reasonable option. If it is, my vote still goes for empty.

If I understand the nullptr proposal correctly, the intent is that
nullptr shouldn't match an unconstrained T* argument. The main reason
being that there's no obvious way to deduce type T.

If that's the case, I agree that the empty ctor is preferable. I don't
see a compelling use case where you actually want to keep a use-count
for null pointers, so it's better to choose the less expensive solution.

Quote:

2) Should this constructor be explicit? If not, we would probably want
to define operator== and operator!= that take a shared_ptr and a nullptr_t.

If it constructs an empty shared_ptr, it should be implicit. Users want
this:

void f( shared_ptr<X> px );

int main()
{
f( nullptr );
}

to work.

Never thought of that. In fact I was going to suggest to make the ctor
explicit. But your example has some beauty in it.

About operators == and !=, it would be good if tests like "if(p ==
nullptr)" and "if(p != nullptr)" were as efficient as "if(!p)" and
"if(p)" respectively, so I would add overloads, avoiding the
construction of a temporary.

Quote:
3) Would we want to have a constructor that takes a nullptr_t and a
destructor object? I'm not sure what use one of these would be, except
maybe to simulate a Java finally block and run code when we leave a scope
for any reason.

No, I don't think that we want it (but we might have it anyway, in
which case we probably don't want to prohibit it, either).

I think it could be useful for the shared_ptr-as-scopeguard idiom. For
example:

shared_ptr<void> guard(nullptr, cleanup);

is more readable than

shared_ptr<void> guard(static_cast<void*>(0), cleanup);

The two-parameter reset() is less used for this idiom, but should also
be overloaded for consistency.

Just my opinion,

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Wed Nov 15, 2006 4:42 am    Post subject: Re: shared_ptr and nullptr Reply with quote

Andrei Polushin ha scritto:

Quote:
// Partial specialization cases
//
template<typename T> class X { };
template<typename T> class X<T*> X { };
template<typename T> class X<T::*> X { };
X<nullptr_t> x; // error, ambiguous; nullptr_t is both a pointer
// and pointer-to-member type, so it.s undecidable
// which partial specialization to use

The last case is "ambiguous", and on page 5 they say that

nullptr_t matches both a T* and a T::* partial specialization.
If it matches two partial specializations of the same template,
the result is ambiguous because neither partial specialization
is more specialized than the other.

Thus the following is unambiguous:

template<typename T> class X { };
template<typename T> class X<T*> X { };
X<nullptr_t> x;

I believe the paper is defective because while it explicitly says that
nullptr_t matches both T* and T::*, but doesn't specify for which T!
Consider this:

template<typename T> struct X
{
X() { cout << "main " << typeid(T).name() << "\n";
};

template<typename T> struct X<T*>
{
X() { cout << "specialization " << typeid(T).name() << "\n";
};

X<nullptr_t> x;

what should be the expected output of this code? The compiler must
instantiate the template, either from the main definition of from the
specialization. But if nullptr_t matches the specialization, the
compiler *must* deduce T. Is it void? Is it some other type? Any choice
is arbitrary. Is T nullptr_t itself? It can't be, because nullptr_t* is
a valid type.

IMHO, the only reasonable solution is that nullptr_t should *not* match
the specialization but the main definition must be chosen with T =
nullptr_t.

In the specific case of shared_ptr, you have to consider that the
constructor:

template<class Y> shared_ptr(Y *p);

is equivalent to use a deleter object that eventually calls

delete static_cast<Y*>(p);

and not

delete static_cast<T*>(p);

so the choice of Y is not irrelevant.

Am I missing something?

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Andrei Polushin
Guest





PostPosted: Wed Nov 15, 2006 6:27 am    Post subject: Re: shared_ptr and nullptr Reply with quote

In context of N1601, the nullptr proposal,
Andrei Polushin wrote:
Quote:
if nullptr_t is a combination of both types, it is defined in terms
of both declarations:

T1 * D1
T2 :: * D2

Alberto Ganesh Barbati wrote:
Quote:
I believe the paper is defective because while it explicitly says that
nullptr_t matches both T* and T::*, but doesn't specify for which T!

I believe it cannot specify which T, because it specifies that T is
both T1 and T2. Both types have the opposite characteristics.

Quote:
Consider this:

template<typename T> struct X
{
X() { cout << "main " << typeid(T).name() << "\n";
};

template<typename T> struct X<T*
{
X() { cout << "specialization " << typeid(T).name() << "\n";
};

X<nullptr_t> x;

what should be the expected output of this code? The compiler must
instantiate the template, either from the main definition of from the
specialization. But if nullptr_t matches the specialization, the
compiler *must* deduce T. Is it void? Is it some other type? Any choice
is arbitrary.

In the the specialization for <T*>, the type T is T1, and the pointer
to T1 should be convertible to the pointer to any other type. We've
recently discussed what the type could it be:

http://groups.google.com/group/comp.std.c++/msg/0b607e99c3481f44
http://groups.google.com/group/comp.std.c++/msg/fa3b0573bade9026
http://groups.google.com/group/comp.std.c++/msg/ccf51aad08b8ae1b

Type T2 is the opposite: a pointer to any other type should be
convertible to the pointer to T2. Type T2 is almost like "void",
without the following limitations:

- inability to inherit from void
- inability to declare pointers to members of void
- inability to declare reference to void


Quote:
Is T nullptr_t itself? It can't be, because nullptr_t* is
a valid type.

It's valid in N1601, but there was no reason to allow it.


Quote:
IMHO, the only reasonable solution is that nullptr_t should *not* match
the specialization but the main definition must be chosen with T =
nullptr_t.

The questions:

1. Is it pointer? If it is pointer,
why doesn't it match the specialization for <T*>?

2. Is it useful in generic programming?

The problem with shared_ptr is the problem that will arise each time
when we will have a template function with parameter of pointer or
pointer-to-member type:

void f(char*);
template<class T> void g(T* p) { f(p); }

g(NULL); // allowed
g(nullptr); // disallowed?

Do you suggest to add an overload for nullptr_t, or is it what we
really want to avoid with nullptr?

And what if I have several parameters of pointer or pointer-to-member
type:

template <class T1, class T2>
int f(T1* p, T2::* pm) {
if (p && pm) {
return p->*pm;
}
return 0;
}

f(p, pm); // ok
f(p, nullptr); // error
f(nullptr, pm); // error
f(nullptr, nullptr); // error

Should I provide another 3 overloads for nullptr_t?


--
Andrei Polushin

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Greg Herlihy
Guest





PostPosted: Wed Nov 15, 2006 6:36 am    Post subject: Re: shared_ptr and nullptr Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
Consider this:

template<typename T> struct X
{
X() { cout << "main " << typeid(T).name() << "\n";
};

template<typename T> struct X<T*
{
X() { cout << "specialization " << typeid(T).name() << "\n";
};

X<nullptr_t> x;

what should be the expected output of this code?

This program prints out an implementation-defined name for an
implementation-defined type - so its expected output would vary across
implementations.

Quote:
The compiler must
instantiate the template, either from the main definition of from the
specialization. But if nullptr_t matches the specialization, the
compiler *must* deduce T. Is it void? Is it some other type? Any choice
is arbitrary. Is T nullptr_t itself? It can't be, because nullptr_t* is
a valid type.

Since nullptr_t is an implementation-defined typedef, the T deduced for
the pointer specialization of X, would be an implementation-defined
type.

Quote:
IMHO, the only reasonable solution is that nullptr_t should *not* match
the specialization but the main definition must be chosen with T =
nullptr_t.

Since nullptr_t is a pointer type, it must match the T* specialization.
There is no other, legal alternative.

Quote:
In the specific case of shared_ptr, you have to consider that the
constructor:

template<class Y> shared_ptr(Y *p);

is equivalent to use a deleter object that eventually calls

delete static_cast<Y*>(p);

and not

delete static_cast<T*>(p);

so the choice of Y is not irrelevant.

Nor is it important - which is the reason why the choice for Y's type
is not specified, but instead left as an implementation-level detail.

Greg

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Wed Nov 15, 2006 9:54 pm    Post subject: Re: shared_ptr and nullptr Reply with quote

Greg Herlihy ha scritto:
Quote:
Alberto Ganesh Barbati wrote:
Consider this:

template<typename T> struct X
{
X() { cout << "main " << typeid(T).name() << "\n";
};

template<typename T> struct X<T*
{
X() { cout << "specialization " << typeid(T).name() << "\n";
};

X<nullptr_t> x;

what should be the expected output of this code?

This program prints out an implementation-defined name for an
implementation-defined type - so its expected output would vary across
implementations.

That's reasonable. However, it's not specified in the paper. I know the
paper is two years old, so there surely was a lot of discussion about it
that I'm not aware of. (Ok, I could google for that, but maybe time has
come for a new paper that integrates those discussions.)

Quote:
IMHO, the only reasonable solution is that nullptr_t should *not* match
the specialization but the main definition must be chosen with T =
nullptr_t.

Since nullptr_t is a pointer type, it must match the T* specialization.
There is no other, legal alternative.

There is no alternative according to the new knowledge you have introduced.

Quote:
In the specific case of shared_ptr, you have to consider that the
constructor:

template<class Y> shared_ptr(Y *p);

is equivalent to use a deleter object that eventually calls

delete static_cast<Y*>(p);

and not

delete static_cast<T*>(p);

so the choice of Y is not irrelevant.

Nor is it important - which is the reason why the choice for Y's type
is not specified, but instead left as an implementation-level detail.

Well, it is. shared_ptr requires that Y must be a complete type. That
would mean that the implementation-defined type should be complete as
well, or we would incur in undefined behavior.

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Greg Herlihy
Guest





PostPosted: Thu Nov 16, 2006 5:57 am    Post subject: Re: shared_ptr and nullptr Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
Greg Herlihy ha scritto:
Alberto Ganesh Barbati wrote:
Consider this:

template<typename T> struct X
{
X() { cout << "main " << typeid(T).name() << "\n";
};

template<typename T> struct X<T*
{
X() { cout << "specialization " << typeid(T).name() << "\n";
};

X<nullptr_t> x;

what should be the expected output of this code?

This program prints out an implementation-defined name for an
implementation-defined type - so its expected output would vary across
implementations.

That's reasonable. However, it's not specified in the paper. I know the
paper is two years old, so there surely was a lot of discussion about it
that I'm not aware of. (Ok, I could google for that, but maybe time has
come for a new paper that integrates those discussions.)

The typedef is specified in the paper. Specifically, the nullptr_t
typedef is described (as an addition to §8.1) on page 9 of the nullptr
proposal (N1601). I have no other information about nullptr apart from
this document.

Quote:
IMHO, the only reasonable solution is that nullptr_t should *not* match
the specialization but the main definition must be chosen with T =
nullptr_t.

Since nullptr_t is a pointer type, it must match the T* specialization.
There is no other, legal alternative.

There is no alternative according to the new knowledge you have introduced.

The "new knowledge" for which I should be credited - is the revelation
that the final page of a proposal may contain information other than
the biliography, notes or acknowledgments of the proposal. :-)

Quote:
In the specific case of shared_ptr, you have to consider that the
constructor:

template<class Y> shared_ptr(Y *p);

is equivalent to use a deleter object that eventually calls

delete static_cast<Y*>(p);

and not

delete static_cast<T*>(p);

so the choice of Y is not irrelevant.

Nor is it important - which is the reason why the choice for Y's type
is not specified, but instead left as an implementation-level detail.

Well, it is. shared_ptr requires that Y must be a complete type. That
would mean that the implementation-defined type should be complete as
well, or we would incur in undefined behavior.

More precisely, passing an incomplete Y type has an undefined effect
upon the Library. The Library, after all, must abide by the same C++
language rules as any other source code - and has no license to specify
additional, undefined behavior not already undefined by the rules of
the language.

In this case it would seem to make the most sense for shared_ptr to
have a (non-template), delegating constructor (taking a nullptr_t
parameter) that simply default-constructs an empty shared_ptr object.

Greg


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Fri Nov 17, 2006 1:33 am    Post subject: Re: shared_ptr and nullptr Reply with quote

Greg Herlihy ha scritto:
Quote:
Alberto Ganesh Barbati wrote:
Greg Herlihy ha scritto:
Alberto Ganesh Barbati wrote:
Consider this:

template<typename T> struct X
{
X() { cout << "main " << typeid(T).name() << "\n";
};

template<typename T> struct X<T*
{
X() { cout << "specialization " << typeid(T).name() << "\n";
};

X<nullptr_t> x;

what should be the expected output of this code?
This program prints out an implementation-defined name for an
implementation-defined type - so its expected output would vary across
implementations.
That's reasonable. However, it's not specified in the paper. I know the
paper is two years old, so there surely was a lot of discussion about it
that I'm not aware of. (Ok, I could google for that, but maybe time has
come for a new paper that integrates those discussions.)

The typedef is specified in the paper. Specifically, the nullptr_t
typedef is described (as an addition to §8.1) on page 9 of the nullptr
proposal (N1601). I have no other information about nullptr apart from
this document.

I've seen page 9. That typedef is only a partial answer to my request.
It says that nullptr_t is an implementation defined type, but it doesn't
say anything about T when nullptr_t matches T* as a template parameter.
Same thing for member pointers because matching a member pointer
involves more than one type (an additional type for a pointer to data
members and one or more additional types for a pointer to member function).

I seems that my answer to Andrei's post has been lost... I'll repost it,
as it contained some more thoughts of mine about this issues.

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Fri Nov 17, 2006 4:17 am    Post subject: nullptr (was Re: shared_ptr and nullptr) Reply with quote

[note to Mods: this is a repost]

Andrei Polushin ha scritto:
Quote:
In context of N1601, the nullptr proposal,
Andrei Polushin wrote:
if nullptr_t is a combination of both types, it is defined in terms
of both declarations:

T1 * D1
T2 :: * D2

Alberto Ganesh Barbati wrote:
I believe the paper is defective because while it explicitly says that
nullptr_t matches both T* and T::*, but doesn't specify for which T!

I believe it cannot specify which T, because it specifies that T is
both T1 and T2. Both types have the opposite characteristics.

I know that T1 and T2 have opposite characteristics, but as nullptr
can't match both at the same time, it is reasonable to expect the paper
to at least specify T1 and T2 separately. This lack of
specification is a defect, IMHO. For example, the paper could say that
T1 and T2 are implementation-defined types satisfying a certain list of
properties. Even that might be enough.

Quote:
Is T nullptr_t itself? It can't be, because nullptr_t* is
a valid type.

It's valid in N1601, but there was no reason to allow it.


Nor I see a reason to disallow it.

Quote:

IMHO, the only reasonable solution is that nullptr_t should *not*
match
the specialization but the main definition must be chosen with T =
nullptr_t.

The questions:

1. Is it pointer? If it is pointer,
why doesn't it match the specialization for <T*>?

My understanding was that nullptr wasn't actually a pointer, but simply
"convertible" to any pointer type. It seems I was wrong.

Quote:
2. Is it useful in generic programming?

The problem with shared_ptr is the problem that will arise each time
when we will have a template function with parameter of pointer or
pointer-to-member type:

void f(char*);
template<class T> void g(T* p) { f(p); }

g(NULL); // allowed
g(nullptr); // disallowed?

Not quite... g(NULL) is actually disallowed, because the compiler can't
deduce T. So this example simply shows that if nullptr doesn't match T*
then we are stuck with the ugly idiom

g((char*)NULL);

which nullptr was expected to fix.

As we are discussing about the type of nullptr, what would be the
expected behavior of

tr1::is_pointer<nullptr_t>
tr1::is_member_object_pointer<nullptr_t>
tr1::is_member_function_pointer<nullptr_t>

and

tr1::remove_pointer<nullptr_t> ?

In particular, the latter seems a bit problematic, yet very interesting.

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Joe Gottman
Guest





PostPosted: Fri Nov 17, 2006 5:48 am    Post subject: Re: nullptr (was Re: shared_ptr and nullptr) Reply with quote

"Alberto Ganesh Barbati" <AlbertoBarbati (AT) libero (DOT) it> wrote in message
news:ZJF6h.43747$uv5.300164 (AT) twister1 (DOT) libero.it...
Quote:
Andrei Polushin ha scritto:
In context of N1601, the nullptr proposal,
Andrei Polushin wrote:
if nullptr_t is a combination of both types, it is defined in terms
of both declarations:

T1 * D1
T2 :: * D2

Alberto Ganesh Barbati wrote:
I believe the paper is defective because while it explicitly says that
nullptr_t matches both T* and T::*, but doesn't specify for which T!

I believe it cannot specify which T, because it specifies that T is
both T1 and T2. Both types have the opposite characteristics.

What is the advantage of this over just having nullptr_t be a simple type
with defined conversions to all pointer and member-pointer types? As the
previous poster noted, having nullptr_t be of both pointer and
member-pointer type breaks the perfectly reasonable assumption in the
type_traits library that the sets of pointer types and member-pointer types
are disjoint. Also, many functions that take a pointer as a parameter have
code that looks like the following:

template <class T>
void usePointer(T *p)
{
if (!p) {
return; // or throw an exception
} else {
//Do something with *p
}
}

The problem is that the code under "Do something with *p" can do literally
anything. It can call any function with *p as a parameter and any number of
other parameters of any type before and after. It can call a member
function on p of any name with any number of parameters. And yet somehow,
in all cases, this code must compile with T = T1. If the concepts proposal
is accepted then this becomes even weirder.

It seems to me that it would be much simpler for all involved, compile
writers, library writers, and casual users, if nullptr_t were just a simple
type with an automatic conversion to any pointer or member-pointer type.
Then the rule for using it would be easy to understand: if your overload set
has one function that takes a pointer parameter then nullptr converts to
that type. If it has two or more or is a template than you need to write an
extra overload that takes a nullptr_t parameter.

Joe Gottman


---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Fri Nov 17, 2006 9:08 am    Post subject: nullptr (was Re: shared_ptr and nullptr) Reply with quote

Andrei Polushin ha scritto:
Quote:
In context of N1601, the nullptr proposal,
Andrei Polushin wrote:
if nullptr_t is a combination of both types, it is defined in terms
of both declarations:

T1 * D1
T2 :: * D2

Alberto Ganesh Barbati wrote:
I believe the paper is defective because while it explicitly says that
nullptr_t matches both T* and T::*, but doesn't specify for which T!

I believe it cannot specify which T, because it specifies that T is
both T1 and T2. Both types have the opposite characteristics.

I know that T1 and T2 have opposite characteristics, but as nullptr
can't match both at the same time, it is reasonable to expect the paper
to at least specify T1 and T2 separately. This lack of
specification is a defect, IMHO. For example, the paper could say that
T1 and T2 are implementation-defined types satisfying a certain list of
properties. Even that might be enough.

Quote:
Is T nullptr_t itself? It can't be, because nullptr_t* is
a valid type.

It's valid in N1601, but there was no reason to allow it.


Nor I see a reason to disallow it.

Quote:

IMHO, the only reasonable solution is that nullptr_t should *not* match
the specialization but the main definition must be chosen with T =
nullptr_t.

The questions:

1. Is it pointer? If it is pointer,
why doesn't it match the specialization for <T*>?

My understanding was that nullptr wasn't actually a pointer, but simply
"convertible" to any pointer type. It seems I was wrong.

Quote:
2. Is it useful in generic programming?

The problem with shared_ptr is the problem that will arise each time
when we will have a template function with parameter of pointer or
pointer-to-member type:

void f(char*);
template<class T> void g(T* p) { f(p); }

g(NULL); // allowed
g(nullptr); // disallowed?

Not quite... g(NULL) is actually disallowed, because the compiler can't
deduce T. So this example simply shows that if nullptr doesn't match T*
then we are stuck with the ugly idiom

g((char*)NULL);

which nullptr was expected to fix.

As we are discussing about the type of nullptr, what would be the
expected behavior of

tr1::is_pointer<nullptr_t>
tr1::is_member_object_pointer<nullptr_t>
tr1::is_member_function_pointer<nullptr_t>

and

tr1::remove_pointer<nullptr_t> ?

In particular, the latter seems a bit problematic, yet very interesting.

Ganesh

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.