3

I've changed the question title and body see if it suits better :).


I read a member function signature on cppreference: unique_ptr/reset.

void reset( pointer ptr = pointer() ) noexcept;

and pointer is a member type of unique_ptr, documented as

pointer | std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T*. Must satisfy NullablePointer

What I've learnt in the comments:

  1. pointer ptr = pointer() is somehow equivalent to e.g. int, using pointer = int*; pointer ptr = pointer()
  2. And if it's a built-in type like int, then ptr is a zero-initialized variable. I get a int* pointer with 0/NULL/nullptr here.
  3. There is not a "raw" statement for using pointer = int*; pointer ptr = pointer(), which is that int* ptr = int*() won't work.

I also read Do built-in types have default constructors? and that helps a lot.


I want to know a bit more about this behaviour(a built-in type can be constructed in a custom class way), if it can be explained in more details:

using pointer = int*; pointer ptr = pointer()

Seriously no "raw" syntax for this statment? I used to think that everything use a typedef or using could be written down with a "raw" version. Like a one-to-one mapping.

Rick
  • 7,007
  • 2
  • 49
  • 79
  • 2
    Expect null pointer. – Evg Dec 11 '19 at 13:01
  • @Evg Why? How? ... QAQ – Rick Dec 11 '19 at 13:02
  • 4
    Does this answer your question? [What is the default constructor for C++ pointer?](https://stackoverflow.com/questions/936999/what-is-the-default-constructor-for-c-pointer) – Evg Dec 11 '19 at 13:02
  • @Evg Sorry I don't understand that linked question. I don't see arguments similar like `pointer ptr = pointer()` :( – Rick Dec 11 '19 at 13:07
  • `pointer` is `data_type` [and](https://stackoverflow.com/a/937119/1625187) "The expression `data_type()` evaluates to a default-initialized object. In case of non-POD types, the default constructor is invoked, but in case of POD types, such as pointers, default initialization is equivalent to zero initialization." – Evg Dec 11 '19 at 13:08
  • @Evg Ah I see. Let me check again. I just noticed that `pointer` is a type member of `unique_ptr`. Sorry I didn't notice that. – Rick Dec 11 '19 at 14:01
  • 3
    @Evg: That statement (partly due to its age, presumably) is confusing default-initialization with value-initialization, which is what `T()` does. – Davis Herring Dec 11 '19 at 14:03
  • @DavisHerring, agree. – Evg Dec 11 '19 at 14:09
  • @Evg But how does that work ? For example, I can't initialize a pointer with `int* p = int*()` – Rick Dec 11 '19 at 14:11
  • The definition of `pointer` is `std::remove_reference::type::pointer if that type exists, otherwise T*. Must satisfy NullablePointer`. `T* ptr = T*()` ? – Rick Dec 11 '19 at 14:12
  • Unless you use some fancy custom deleter, it is just `T*`. Try this for `int`: `using T = int*; T p = T();` or `int* p = (int*){};`. – Evg Dec 11 '19 at 14:16
  • @Evg But what's the equivalent of that without using `using`? using `using` only makes more confusion to me.. There must be a "raw" format. – Rick Dec 11 '19 at 14:18
  • @Rick No, there need not be, and there isn't one. As a much more gratuitious example, `a.~int()` is an error, but `a.~T()` is a no-op for `int a; using T = int;`. – Deduplicator Dec 11 '19 at 14:19
  • @Deduplicator ...seriously? I can't write that expression with raw type? OMG – Rick Dec 11 '19 at 14:20
  • There are some syntactic limitations. You should either use a `typedef`/`using` or curly braces. – Evg Dec 11 '19 at 14:21
  • I'm not sure about the correct quote from the standard. But if the type name is not a single word, you can't say `some type()` like `unsigned int()` or `int*()`. But if it is a single word like `pointer`, you can say `pointer()`, and if `pointer` is just a plain pointer like `int*`, `pointer()` means zero-initialization as explained in the linked question. – Evg Dec 11 '19 at 14:29
  • See this: https://en.cppreference.com/w/cpp/language/value_initialization - "4) otherwise, the object is zero-initialized." – Evg Dec 11 '19 at 14:32
  • 1
    @Evg: `(int*){}` is a compound literal; those exist in C but not C++. – Davis Herring Dec 11 '19 at 14:35
  • @DavisHerring, thanks. It seems to be supported by Gcc and Clang as an extension. – Evg Dec 11 '19 at 14:38
  • @Evg Thanks. Things get much clearer after I read this post [Do built-in types have default constructors?](https://stackoverflow.com/questions/5113365/do-built-in-types-have-default-constructors). Also I think `int* p = (int*){};` may be the "raw" pattern(I just ran it on my machine and it compiles), as someone in that answer says *"So technically there are no constructors for basic-POD types. But for all intents and purposes they act just like they have a copy constructor and default constructor (**when initialized with the braces**)."* – Rick Dec 11 '19 at 16:58
  • As Davis noted above, `(int*){}` is not really standard C++, it is C. `using T = int*; T();` is the example with a raw pointer. You can't write it without `T`, because `int*` is not single-word type name. See also [this question](https://stackoverflow.com/questions/53336344/braced-init-list-and-unsigned-types). – Evg Dec 11 '19 at 17:08

1 Answers1

2

There is no need for the "raw" syntax as you put it, since pointers can be zero initialized with a 0.

int *p = 0; // nullptr

I guess it might be useful for template argument deduction, but we already have a syntax for that: (int*)0. There isn't really a need to add yet more syntax for something small like that (or maybe someone forgot to add it; but either way, it's unnecessary now).

The T(...) syntax is mostly used to initialize objects of user-defined types.

I used to think that everything use a typedef or using could be written down with a "raw" version.

Here's another example:

int a;
a.~int(); // syntax error

using Int = int;
a.~Int(); // ok!

The first statement is disallowed because it's a no-op. The second isn't because in a generic context it might do something (destroy the object) instead of being a no-op. Since the language doesn't want to unnecessarily restrict this going through an alias is allowed.

It's for this same reason that pointer() is allowed even if you can't write out the syntax: If it would be disallowed it would be a pain to work in a generic context.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
  • Makes a good point. A friend in chatroom also mentioned that "generic" part. https://chat.stackoverflow.com/transcript/message/48085012#48085012 – Rick Dec 11 '19 at 18:42
  • What's do you mean by saying "we alreay have `(int*)0`" ? Sorry I don't remember much about the template part. I just tested on my machine. I can only use `(int*)0` to initialize built-in types like `int, int*` , but not for custom class type. `(T)0` doesn't seem to be a substitude of `using pointer = int*; pointer ptr = pointer()`. – Rick Dec 11 '19 at 18:46
  • Another question: "The first statement is disallowed because it's a no-op. ". So `no-p == not allowed`? I know little about the `no-op` concept and how it interacts with the language. – Rick Dec 11 '19 at 18:53
  • @Rick `(T)0` yeah just built-in types. It's a no-op, so allowing it would be misleading since it doesn't do anything – Rakete1111 Dec 11 '19 at 19:02