Does 'Auto' Type Assignments of a Pointer in C++11 Require '*'

Does 'auto' type assignments of a pointer in c++11 require '*'?

auto newvar1 = myvector;

// vs:
auto *newvar2 = myvector;

Both of these are the same and will declare a pointer to std::vector<MyClass> (pointing to random location, since myvector is uninitialized in your example and likely contains garbage). So basically you can use any one of them. I would prefer auto var = getVector(), but you may go for auto* var = getVector() if you think it stresses the intent (that var is a pointer) better.

I must say I never dreamt of similar uncertainity using auto. I thought people would just use auto and not think about it, which is correct 99 % of the time - the need to decorate auto with something only comes with references and cv-qualifiers.

However, there is slight difference between the two when modifies slightly:

auto newvar1 = myvector, newvar2 = something;

In this case, newvar2 will be a pointer (and something must be too).

auto *newvar1 = myvector, newvar2 = something;

Here, newvar2 is the pointee type, eg. std::vector<MyClass>, and the initializer must be adequate.

In general, if the initializer is not a braced initializer list, the compiler processes auto like this:

  1. It produces an artificial function template declaration with one argument of the exact form of the declarator, with auto replaced by the template parameter. So for auto* x = ..., it uses

    template <class T> void foo(T*);
  2. It tries to resolve the call foo(initializer), and looks what gets deduced for T. This gets substituted back in place of auto.

  3. If there are more declarators in a single declarations, this is done for all of them. The deduced T must be the same for all of them...

Difference between auto and auto* when storing a pointer

In the snippet you have given there is no difference. The compiler will deduce that p will be a pointer to C, either way.

In a more general case, there is a difference;

auto *p = func();

auto p = func();

The first form will cause an error message if func() returns something that is not a pointer, but the second will not. This is sometimes useful (e.g. in templated code) where there is a need to enforce a requirement that func() return a pointer rather than (say) an int. [Although, admittedly, there are more clear and powerful ways to enforce such a requirement, such as traits].

Why should I use a pointer rather than the object itself?

It's very unfortunate that you see dynamic allocation so often. That just shows how many bad C++ programmers there are.

In a sense, you have two questions bundled up into one. The first is when should we use dynamic allocation (using new)? The second is when should we use pointers?

The important take-home message is that you should always use the appropriate tool for the job. In almost all situations, there is something more appropriate and safer than performing manual dynamic allocation and/or using raw pointers.

Dynamic allocation

In your question, you've demonstrated two ways of creating an object. The main difference is the storage duration of the object. When doing Object myObject; within a block, the object is created with automatic storage duration, which means it will be destroyed automatically when it goes out of scope. When you do new Object(), the object has dynamic storage duration, which means it stays alive until you explicitly delete it. You should only use dynamic storage duration when you need it.
That is, you should always prefer creating objects with automatic storage duration when you can.

The main two situations in which you might require dynamic allocation:

  1. You need the object to outlive the current scope - that specific object at that specific memory location, not a copy of it. If you're okay with copying/moving the object (most of the time you should be), you should prefer an automatic object.
  2. You need to allocate a lot of memory, which may easily fill up the stack. It would be nice if we didn't have to concern ourselves with this (most of the time you shouldn't have to), as it's really outside the purview of C++, but unfortunately, we have to deal with the reality of the systems we're developing for.

When you do absolutely require dynamic allocation, you should encapsulate it in a smart pointer or some other type that performs RAII (like the standard containers). Smart pointers provide ownership semantics of dynamically allocated objects. Take a look at std::unique_ptr and std::shared_ptr, for example. If you use them appropriately, you can almost entirely avoid performing your own memory management (see the Rule of Zero).

Pointers

However, there are other more general uses for raw pointers beyond dynamic allocation, but most have alternatives that you should prefer. As before, always prefer the alternatives unless you really need pointers.

  1. You need reference semantics. Sometimes you want to pass an object using a pointer (regardless of how it was allocated) because you want the function to which you're passing it to have access that that specific object (not a copy of it). However, in most situations, you should prefer reference types to pointers, because this is specifically what they're designed for. Note this is not necessarily about extending the lifetime of the object beyond the current scope, as in situation 1 above. As before, if you're okay with passing a copy of the object, you don't need reference semantics.

  2. You need polymorphism. You can only call functions polymorphically (that is, according to the dynamic type of an object) through a pointer or reference to the object. If that's the behavior you need, then you need to use pointers or references. Again, references should be preferred.

  3. You want to represent that an object is optional by allowing a nullptr to be passed when the object is being omitted. If it's an argument, you should prefer to use default arguments or function overloads. Otherwise, you should preferably use a type that encapsulates this behavior, such as std::optional (introduced in C++17 - with earlier C++ standards, use boost::optional).

  4. You want to decouple compilation units to improve compilation time. The useful property of a pointer is that you only require a forward declaration of the pointed-to type (to actually use the object, you'll need a definition). This allows you to decouple parts of your compilation process, which may significantly improve compilation time. See the Pimpl idiom.

  5. You need to interface with a C library or a C-style library. At this point, you're forced to use raw pointers. The best thing you can do is make sure you only let your raw pointers loose at the last possible moment. You can get a raw pointer from a smart pointer, for example, by using its get member function. If a library performs some allocation for you which it expects you to deallocate via a handle, you can often wrap the handle up in a smart pointer with a custom deleter that will deallocate the object appropriately.

C++ auto keyword. Why is it magic?

auto was a keyword that C++ "inherited" from C that had been there nearly forever, but virtually never used because there were only two possible conditions: either it wasn't allowed, or else it was assumed by default.

The use of auto to mean a deduced type was new with C++11.

At the same time, auto x = initializer deduces the type of x from the type of initializer the same way as template type deduction works for function templates. Consider a function template like this:

template<class T>
int whatever(T t) {
// point A
};

At point A, a type has been assigned to T based on the value passed for the parameter to whatever. When you do auto x = initializer;, the same type deduction is used to determine the type for x from the type of initializer that's used to initialize it.

This means that most of the type deduction mechanics a compiler needs to implement auto were already present and used for templates on any compiler that even sort of attempted to implement C++98/03. As such, adding support for auto was apparently fairly easy for essentially all the compiler teams--it was added quite quickly, and there seem to have been few bugs related to it either.

When this answer was originally written (in 2011, before the ink was dry on the C++ 11 standard) auto was already quite portable. Nowadays, it's thoroughly portable among all the mainstream compilers. The only obvious reasons to avoid it would be if you need to write code that's compatible with a C compiler, or you have a specific need to target some niche compiler that you know doesn't support it (e.g., a few people still write code for MS-DOS using compilers from Borland, Watcom, etc., that haven't seen significant upgrades in decades). If you're using a reasonably current version of any of the mainstream compilers, there's no reason to avoid it at all though.

More recent revisions of the standard have added a few new places that auto can be used. Starting with C++14, you can use auto for the type of a parameter to a lambda:

    [](auto s) { return s + 1; }

This does essentially the same thing as the example above--even though it doesn't explicitly use template syntax, this is basically a template that deduces the type of the parameter, and instantiates the template over that type.

That was convenient and useful enough that in C++20, the same capability was added for normal functions, not just lambdas.

But, just as before all of this really comes down to using the same basic type deduction mechanism as we've had for function templates since C++98. auto allows that to be used in more places, and more conveniently, but the underlying heavy lifting remains the same.

Can I use if (pointer) instead of if (pointer != NULL)?

You can; the null pointer is implicitly converted into boolean false while non-null pointers are converted into true. From the C++11 standard, section on Boolean Conversions:

A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a
prvalue of type
bool. A zero value, null pointer value, or null member pointer value is converted to
false;
any other value is converted to
true
. A prvalue of type
std::nullptr_t
can be converted to a prvalue of
type
bool
; the resulting value is
false
.

Pointer to member variable - auto type in C++

auto is not the solution you're looking for. Types in C++ cannot change at runtime. auto must always be inferred from it's initializer. In your case, there is no initializer so it won't work.

What I suggest to you would be to move the auto into the parameter of a lambda:

void member(string member_string)
{
// Here, the type of `ptr` will be
// inferred when the lambda is called
// ~~~~v~~~~
auto do_magic = [](auto ptr) {
// loop over objects and do some magic with them
};

if(member_string == "time") do_magic(&DETECTOR::time);
if(member_string == "energy") do_magic(&DETECTOR::energy);
if(member_string == "number") do_magic(&DETECTOR::number);
}

The lambda is the equivalent of a function template:

template<typename T>
void do_magic(T ptr) {
// loop over objects and do some magic with them
}

[ERROR ]request for member in which is of pointer type maybe you meant to use - ?) in C BST

A is a ABR**, so a struct noud***, so (*A) is a struct noud** not a struct noud* and (*A)->caracterise is wrong (but (**A)->caracterise legal)

What does ** do in C language?

In C arguments are passed by values. For example if you have an integer varaible in main

int main( void )
{
int x = 10;
//...

and the following function

void f( int x )
{
x = 20;
printf( "x = %d\n", x );
}

then if you call the function in main like this

f( x );

then the parameter gets the value of variable x in main. However the parameter itself occupies a different extent in memory than the argument. So any changes of the parameter in the function do not influence to the original variable in main because these changes occur in different memory extent.

So how to change the varible in main in the function?

You need to pass a reference to the variable using pointers.

In this case the function declaration will look like

void f( int *px );

and the function definition will be

void f( int *px )
{
*px = 20;
printf( "*px = %d\n", *px );
}

In this case it is the memory extent occupied by the original variable x is changed because within the function we get access to this extent using the pointer

    *px = 20;

Naturally the function must be called in main like

f( &x );

Take into account that the parameter itself that is the pointer px is as usual a local variable of the function. That is the function creates this variable and initializes it with the address of variable x.

Now let's assume that in main you declared a pointer for example the following way

int main( void )
{
int *px = malloc( sizeof( int ) );
//..

And the function defined like

void f( int *px )
{
px = malloc( sizeof( int ) );

printf( "px = %p\n", px );
}

As parameter px is a local variable assigning to it any value does not influence to the original pointer. The function changes a different extent of memory than the extent occupied by the original pointer px in main.

How to change the original pointer in the function?
Just pass it by reference!

For example

f( &px );
//...

void f( int **px )
{
*px = malloc( sizeof( int ) );

printf( "*px = %p\n", *px );
}

In this case the value stored in the original pointer will be changed within the function because the function using dereferencing access the same memory extent where the original pointer was defined.

Is auto* useful at compile time or is the auto keyword enough?

None of this “newfangled C++11” has anything to do with efficient compilation, except in very odd corner cases. It’s all there to make it easier for humans to write and comprehend the code. auto* makes it obvious that you have a pointer-typed value, and the compiler only uses it as an additional typecheck criterion, and will issue a diagnostic if the type is not a pointer type – your code is then malformed and it’s a hard error.

I don’t recall offhand if auto* can ever participate as a disambiguator in type deduction, but if it did, that would be the technical reason to use it. Language lawyer, is there a language lawyer on board? :)

Most properly designed projects – even huge ones – should recompile quickly after changes, it’s a matter of proper partitioning of the code and having development builds that leverage such partitioning.

X does not name a type error in C++

When the compiler compiles the class User and gets to the MyMessageBox line, MyMessageBox has not yet been defined. The compiler has no idea MyMessageBox exists, so cannot understand the meaning of your class member.

You need to make sure MyMessageBox is defined before you use it as a member. This is solved by reversing the definition order. However, you have a cyclic dependency: if you move MyMessageBox above User, then in the definition of MyMessageBox the name User won't be defined!

What you can do is forward declare User; that is, declare it but don't define it. During compilation, a type that is declared but not defined is called an incomplete type.
Consider the simpler example:

struct foo; // foo is *declared* to be a struct, but that struct is not yet defined

struct bar
{
// this is okay, it's just a pointer;
// we can point to something without knowing how that something is defined
foo* fp;

// likewise, we can form a reference to it
void some_func(foo& fr);

// but this would be an error, as before, because it requires a definition
/* foo fooMember; */
};

struct foo // okay, now define foo!
{
int fooInt;
double fooDouble;
};

void bar::some_func(foo& fr)
{
// now that foo is defined, we can read that reference:
fr.fooInt = 111605;
fr.foDouble = 123.456;
}

By forward declaring User, MyMessageBox can still form a pointer or reference to it:

class User; // let the compiler know such a class will be defined

class MyMessageBox
{
public:
// this is ok, no definitions needed yet for User (or Message)
void sendMessage(Message *msg, User *recvr);

Message receiveMessage();
vector<Message>* dataMessageList;
};

class User
{
public:
// also ok, since it's now defined
MyMessageBox dataMsgBox;
};

You cannot do this the other way around: as mentioned, a class member needs to have a definition. (The reason is that the compiler needs to know how much memory User takes up, and to know that it needs to know the size of its members.) If you were to say:

class MyMessageBox;

class User
{
public:
// size not available! it's an incomplete type
MyMessageBox dataMsgBox;
};

It wouldn't work, since it doesn't know the size yet.


On a side note, this function:

 void sendMessage(Message *msg, User *recvr);

Probably shouldn't take either of those by pointer. You can't send a message without a message, nor can you send a message without a user to send it to. And both of those situations are expressible by passing null as an argument to either parameter (null is a perfectly valid pointer value!)

Rather, use a reference (possibly const):

 void sendMessage(const Message& msg, User& recvr);


Related Topics



Leave a reply



Submit