5

It's known that defining a heap variable with new gets the pointer without specifying the name:

Var *p = new Var("name", 1);

But I have to clear the variable pointed to by p with delete p later on in the program.

I want to declare a stack variable so it is automatically cleared after function exits, but I only want to get the pointer, and the following:

Var v("name", 1);
Var *p = &v;

is quite tedious, and specifier v will never be referenced.

Can I declare a stack class instance and get its pointer without specifying its name?

Mat
  • 202,337
  • 40
  • 393
  • 406
CDT
  • 73
  • 7
  • `Var *p = Var("name", 1);` does not work? – Patashu Jun 05 '13 at 01:45
  • 7
    Um, do you really need to access the object through a pointer? – Mark Garcia Jun 05 '13 at 01:46
  • 1
    I'll stick my neck out — I think the answer is "No, you can't do that; that is, you cannot define an anonymous variable on the stack". – Jonathan Leffler Jun 05 '13 at 01:52
  • 4
    What's wrong with just using "&v" in the locations where you need a pointer version of it? – kfsone Jun 05 '13 at 04:11
  • What do you mean by 'gets the pointer without specifying the name'? – user207421 Jun 05 '13 at 04:22
  • @JonathanLeffler Are you sure? I'm pretty sure my answer (essentially Patashu's with an `&` operator) accomplishes that, though I could be missing something. – Kyle Strand Jun 05 '13 at 04:54
  • @KyleStrand: yes, I'm pretty sure — see my commentary to your answer. Certainly, your code/answer does not constitute a compelling counter-example; it requires you to suppress an error message from G++ and is demonstrably fragile. – Jonathan Leffler Jun 05 '13 at 05:22
  • What problem are you trying to solve? If you ever start to use clever tricks in your code, that does not improve its clarity, but rather makes the code more obscure, with the sole purpose to save yourself from a bit of extra typing, then you are doing _bad programming_. – Lundin Jun 05 '13 at 06:37

5 Answers5

10

There's two questions hidden in here. The first one is:

Var *p = new Var("name", 1);

But I have to clear the variable pointed to by p with delete p later on in the program.

I want to declare a stack variable so it is automatically cleared after function exits

So here, you're asking how to allocate memory without having to explicitly clean it up afterwards. The solution is to use std::unique_ptr:

std::unique_ptr<Var> p(new Var("name", 1));

Voila! unique_ptr will automatically clean itself up, it has virtually no overhead compared to a raw pointer, and it's overloaded the * and -> operators so you can use it just like a raw pointer. Search for "C++11 smart pointers" if you want to know more.

The second question is:

I only want to get the pointer, and the following:

Var v("name", 1);
Var *p = &v;

is quite tedious, and specifier v will never be referenced.

The important point here is that Var *p = &v is completely unnecessary. If you have a function that requires a pointer, you can use &v on the spot:

void SomeFunc(const Var* p);
// ...
Var v("name", 1);
SomeFunc(&v);

There's no need to put &v in a separate variable before passing it into a function that requires a pointer.

The exception is if the function takes a reference to a pointer (or a pointer to a pointer):

void SomeFunc2(Var*& p);
void SomeFunc3(Var** p);

These types of functions are rare in modern C++, and when you see them, you should read the documentation for that function very carefully. More often than not, those functions will allocate memory, and you'll have to free it explicitly with some other function.

Rick Yorgason
  • 1,616
  • 14
  • 22
  • 1
    One nitpick: you should probably clarify that the object pointed to by `unique_ptr` is *not* on the stack here; it's in the heap. Granted, OP's complaint about the heap was merely that raw pointers don't do automatic clean-up, which of course is solved with `unique_ptr`, but it's still worthwhile to know that heap memory is being allocated and freed here. Additionally, it *can't* be used "just like a raw pointer", because in order to pass it to a function that actually takes a raw pointer (which, as you point out, is probably OP's use case here), you must use `get()`. – Kyle Strand Apr 16 '15 at 01:04
  • (Personally, I'm [not sold on `get()`](http://stackoverflow.com/q/28952141/1858225), though from the votes on that question it appears that most people disagree with me on that.) – Kyle Strand Apr 16 '15 at 01:06
  • Yes, as I mentioned in the answer, there's actually two questions being asked: how can I allocate memory without having to explicitly clean it up? and how can I pass a stack variable to a function expecting a pointer? – Rick Yorgason May 15 '15 at 16:12
  • As far as `get()` goes, I think it's fair to be critical about its use. It's only really necessary when interfacing with legacy code. If you have full control over all the code, you can usually avoid it completely. – Rick Yorgason May 15 '15 at 16:26
  • Right, I wasn't saying your answer doesn't answer the (intended) question, I'm just saying that the stack/heap distinction might not be clear to inexperienced C++ users, so that's probably worth mentioning, especially given the title of the question. – Kyle Strand May 15 '15 at 16:34
  • I'm not actually criticizing use of `get()`; I'm criticizing the fact that the language makes it necessary. Sure, you could avoid writing functions that take raw pointers, just as you can avoid *any* language feature (in any version of C++, modern or not), but [function signatures using raw pointers is actually recommended by Herb Sutter (and probably other experts as well)](https://www.youtube.com/watch?v=xnqTKD8uD64&feature=youtu.be&t=12m10s). – Kyle Strand May 15 '15 at 16:35
2

There's no way to do this by allocating on the stack. However, you can use std::make_shared for the heap:

#include <memory>

std::shared_ptr<Var> p = std::make_shared<Var>();
David G
  • 94,763
  • 41
  • 167
  • 253
  • 1
    Which is totally much more elegant than what the OP already has and definitely less tedious in terms of typing ;) – JustSid Jun 05 '13 at 01:49
  • 6
    This allocates on the free store (heap) not the stack. – Tony Delroy Jun 05 '13 at 01:51
  • @0x499602D2 Um... I'm just looking for a counterpart of `new` for declaring stack variables. – CDT Jun 05 '13 at 02:06
  • @CDT You can't get the address of something without using its name in some way... – David G Jun 05 '13 at 02:13
  • @CDT Why would you expect there to be stack-specific counterpart to a heap-specific construct? That said, it's not actually true that this is impossible to do. – Kyle Strand Jun 05 '13 at 04:46
  • 8
    By default, you should [prefer unique_ptr to shared_ptr](http://herbsutter.com/2013/05/29/gotw-89-solution-smart-pointers/). – Rick Yorgason Jun 05 '13 at 04:49
  • 1
    This allocates on the heap instead of the stack. And even if that was tolerable there is absolutely no need for shared ownership here and a `std::unique_ptr` would be the appropriate solution (hint: this applies to most situations where you're tempted to spam `std::shared_ptr`s). – Christian Rau Jun 05 '13 at 07:37
  • @RickYorgason Given that this rule is not just a matter of taste but a matter of conceptual correctness, I have a hard time bringing the 4 up-votes to your comment in relation to the 1 downvote of this answer. – Christian Rau Jun 05 '13 at 07:39
  • @ChristianRau I've added my own answer which I believe addresses your concerns. – Rick Yorgason Jun 05 '13 at 08:06
  • That will give some over head which seems redundant in this scenario. – Roee Gavirel Jun 05 '13 at 08:16
1

At the cost/risk of being more confusing, you can avoid repeating the type in your code in the question ala:

Var v("name", 1), *p = &v;

You could also potentially use alloca, which is provided by most systems and returns a pointer to stack-allocated memory, but then you have to go through a separate painful step to placement new an object into that memory and do your own object destruction. alloca needs to be called inside the function so it's the function stack on which the object is created, and not during the preparation of function arguments (as the variable's memory may be embedded in the stack area the compiler's using to prepare function arguments), which makes it tricky to wrap into some easily reused facility. You could use macros, but they're evil (see Marshall Cline's C++ FAQ for an explanation of that). Overall - not worth the pain....

Anyway, I recommend sticking with the code in your question and not over-thinking this: using &v a few times tends to be easier, and when it's not it's normally not a big deal if there's an unnecessary identifier for the stack-based variable.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • HOLY CRAP THAT'S BROKEN. alloca is dangerous enough in the first place without people returning pointers to the bit of stack it gave you from inside a constructor. Holy crap! – kfsone Jun 05 '13 at 04:09
  • @kfsone: it's was a shocker par excellence, even if I do say so myself ;-) – Tony Delroy Jun 05 '13 at 04:20
0

I don't think there is a way to overcome it without some overhead (like the shared_ptr). so the shortest way to write it will be:

Var v("name", 1), *p = &v;
Roee Gavirel
  • 18,955
  • 12
  • 67
  • 94
-2

Yes, it's possible to return an address to a temporary (i.e. stack) object and assign it to a pointer. However, the compiler might actually discard the object (i.e. cause that section in memory to be overwritten) before the end of the current scope. (TO CLARIFY: THIS MEANS DON'T DO THIS. EVER.) See the discussion in the comments below about the behavior observed in different versions of GCC on different operating systems. (I don't know whether or not the fact that version 4.5.3 only gives a warning instead of an error indicates that this will always be "safe" in the sense that the pointer will be valid everywhere within the current scope if you compile with that particular version of GCC, but I wouldn't count on it.)

Here's the code I used (modified as per Jonathan Leffler's suggestion):

#include <stdio.h>

class Class {
public:
    int a;
    int b;
    Class(int va, int vb){a = va; b = vb;}
};

int main(){ 
    Class *p = &Class(1, 2);
    Class *q = &Class(3, 4);
    printf("%p: %d,%d\n", (void *)p, p->a, p->b);
    printf("%p: %d,%d\n", (void *)q, q->a, q->b);
}

When compiled using GCC 4.5.3 and run (on Windows 7 SP1), this code printed:

0x28ac28: 1,2
0x28ac30: 3,4

When compiled using GCC 4.7.1 and run (on Mac OS X 10.8.3), it printed:

0x7fff51cd04c0: 0,0
0x7fff51cd04d0: 1372390648,32767

In any case, I'm not sure why you wouldn't just declare the variable normally and use &v everywhere you need something "pointer-like" (for instance, in functions that require a pointer as an argument).

Kyle Strand
  • 15,941
  • 8
  • 72
  • 167
  • 1
    When I compile your code in a file `clash.cpp`, GCC 4.7.1 (`g++ -Wall -Wextra` says: `clash.cpp: In function ‘int main()’:` and `clash.cpp:11:26: error: taking address of temporary [-fpermissive]`. Note that this is an error with 4.7.1 (which version did you use?) I think it is trying to tell you that the duration of the temporary is the end of the statement, so the pointer points at nothing after the statement is complete. To get it to compile, I had to add `-fpermissive`. – Jonathan Leffler Jun 05 '13 at 05:11
  • When I run this minor variation of your code: `int main(){ Class *p = &Class(1, 2); Class *q = &Class(3, 4); printf("%p: %d,%d\n", (void *)p, p->a, p->b); printf("%p: %d,%d\n", (void *)q, q->a, q->b); }` I get garbage output. Without the `%p` printing, (somewhat to my surprise) the code printed `1,2` and `3,4`, but with it, I got: `0x7fff51cd04c0: 0,0` and `0x7fff51cd04d0: 1372390648,32767`. (GCC/G++ 4.7.1 on Mac OS X 10.8.3) – Jonathan Leffler Jun 05 '13 at 05:19
  • @JonathanLeffler Wacky. I'm using 4.5.3, and it's definitely not an error in that version. I get `0x28ac28: 1,2` and `0x28ac30: 3,4`. – Kyle Strand Jun 05 '13 at 06:06
  • (I'm using Cygwin on a Windows 7 SP1.) – Kyle Strand Jun 05 '13 at 06:10
  • 2
    This is the trouble with undefined behaviour; it can sometimes seem to work as you expected...until you move the code to a different machine or different compiler on the same machine. According to the Cygwin setup program, there is a `cygwin64-gcc` at v4.8.0, and a `gcc4` at v4.7.2 (though it defaults to the 4.5.3 version), and plain `gcc` at an archaic v3.4.4. Maybe an upgrade is in order...or maybe not if you've ever relied on this behaviour. (NB: it is an error in 4.7.1 with or without the `-Wall -Wextra` options; it ceases to be an error with `-fpermissive`.) – Jonathan Leffler Jun 05 '13 at 06:17
  • @JonathanLeffler I've never even compiled anything with much more complexity (or importance) than a Hello World on this machine, so...yep, updating. (And I didn't know whether this was undefined or not, so it's nice to see that, yep, it is.) – Kyle Strand Jun 05 '13 at 06:24
  • It works, but it's out of specification, isn't it? the object may die in the same line of it's creation... but I still think it's the best solution for now... – Wagner Patriota Jun 05 '13 at 06:27
  • 2
    @WagnerPatriota: no; it is not the best solution because it is relying on undefined behaviour. Relying on undefined behaviour is dangerous — very dangerous. It is dangerous to your sanity; it is dangerous to your program and its data. – Jonathan Leffler Jun 05 '13 at 06:37
  • yes, I agree. I wrote it before read your comment. When I mean it's the best solution, it's because is the CLOSEST, but still wrong. – Wagner Patriota Jun 05 '13 at 06:48
  • 1
    @WagnerPatriota: this is very seriously wrong - not just something that might actually exhibit undefined behaviour on some weird system but can be expected to work reliably on all modern mainstream machines (as quite a few C++ undefined behaviours are) - rather, this is of the "if it works at all for anyone it's already a fluke and just change the optimiser level or add a few more variables elsewhere in the function and watch it crash and burn" variety. – Tony Delroy Jun 05 '13 at 07:02