5

Example:

Class *_obj1;
Class *_obj2;

void doThis(Class *obj) {}

void create() {
    Class *obj1 = new Class();
    Class obj2;

    doThis(obj1);
    doThis(&obj2);

    _obj1 = obj1;
    _obj2 = &obj2;
}

int main (int argc, const char * argv[]) {

    create();

    _obj1->doSomething();
    _obj2->doSomething();

    return 0;
}

This creates 2 objects, creates pointers to them, then main() calls a method on each. The Class object creates a char* and stores the C string "Hello!" in it; the ~Class() deallocator frees the memory. The doSomething() method prints out "buff: %s" using printf(). Simple enough. Now if we run it we get this:

Dealloc
Buff: Hello!
Buff: ¯ø_ˇ

Obviously the stack object does not work here - it's obvious that when the function exits the pointer _obj2 is pointing at a location in the stack. This is why I used heap objects in my previous question, which people told me was "stupid".

So, the first question is: if how can I convert the stack object (obj2) to a heap object so it's not deallocated after create() exits? I want a straight answer, not an arrogant "you're doing it wrong" as so many have done. Because in this case stack objects cannot work so heap objects seem to be the only way. EDIT: Also, converting back to a stack object would be useful as well.

The second question: the specific example of heap objects being "wrong" was creating a new vector<string>* using the new operator. If dynamically allocating STL objects is wrong, then what's the right way? Obviously if you create them as stack objects it fails because they're immediately deallocated, but I've been told (again, by a very high-ranking member) that dynamically allocating them can corrupt the heap. So what's the right way to do it?

trincot
  • 317,000
  • 35
  • 244
  • 286
jstm88
  • 3,335
  • 4
  • 38
  • 55
  • 4
    Your other question was closed because *it* was filled with pointless ranting. If you want to get a real question going, edit your old question to be on topic and acceptable, not ask a new question. In case this is a *real* question and not just a flame bait, “get a good C++ book” is the qualitatively best answer you can hope for. This is a complex subject, and an answer on this platform *cannot* do it justice. – Konrad Rudolph Feb 20 '11 at 18:00
  • 3
    If you want help. Stop being rude and ask the question nicely. – Martin York Feb 20 '11 at 18:01
  • 3
    if people tell you "you obviously need to read a C++ book" may be there is a point in it? – Andrey Feb 20 '11 at 18:03
  • Note that the initial issue was due to some high-ranking members making comments (such as "it is almost certainly wrong to use a dynamically allocated vector object", "If you've also done this elsewhere in your code, you very likely have messed up the heap", and "Nobody said using a dynamic vector will mess up the heap. However, everybody that doing [sic] so is stupid"). Note all 3 comments are by the same person (there's a contradiction between 2 and 3). I want to know why this is (or not) and if so, what the "right" way is, because heap vectors are sometimes the only way to do things. – jstm88 Feb 20 '11 at 18:15
  • "Heap vectors are sometimes the only way to do things": true. I'd guess that what other respondents were untactfully saying is that *often*, heap objects can be avoideded in favor of stack objects, and that in these cases, you'll find the resulting code easier to maintain since you've obviated the need for extra memory management code (ownership / deallocation), and removed a potential source of memory leakage. – Ben M Feb 20 '11 at 18:19
  • 1
    There is no contradiction between the two statements. The code in question didn’t cause a heap corruption (and nobody said that) but using heap allocation spuriously will drastically increase the risk of an error that will in turn cause heap corruption. Apart from that, sbi’s use of the word “stupid” was … well, stupid, since lack of knowledge isn’t the same as stupidity. In his defense, you seriously flame baited them so why are you surprised when someone took the bait? – Konrad Rudolph Feb 20 '11 at 18:28
  • 1
    @Konrad: To be fair, I had used the word _"stupid"_ exactly __once__, [in a comment](http://stackoverflow.com/questions/5019775/5054081#5054081), when paraphrasing and summarizing what I and others had said. In [my original answer](http://stackoverflow.com/questions/5019775/5019964#5019964) I said that this _"is almost certainly wrong"_. – sbi Feb 20 '11 at 19:22
  • In the very same comment where I used that word, I also said "I suggest you search for questions explaining what to use dynamically allocated objects for. I'm sure it's been asked many times before." The guy seems to have taken this as a hint to go and post a lengthy rant about how, "in C++, the designers chose to add the pointless complexity of stack objects", based on his assumption that "[the C++ designers were much more confused than even I thought](http://stackoverflow.com/questions/5019775#5019964)". I have told him several times since that he should _ask_ in order to learn. To no avail. – sbi Feb 20 '11 at 19:33
  • Wow, @jfm429, you are a truly master of misunderstanding. As everyone can see who follows your link, my original answer says "If you've also done this elsewhere in your code, you very ___likely have messed up the heap___, which is the only case I can think of when `new` would crash." [Bold text as in original statement.] This still stands. In all of your three questions nobody brought up anything against it, and others before and after me were supporting it. I have nothing to admit, except that you seem to be unable to get a point even when it's smacking you on the forehead. – sbi Feb 20 '11 at 19:52
  • @BenM: The thing is that `std::vector` will ___always have its data on the heap___, even when you create objects of it on the stack, so the notion of "heap vector" is a red herring. – sbi Feb 20 '11 at 19:57
  • sbi: Your answer was misleading because your wording suggests that the act of creating a dynamic vector elsewhere was what messed up the heap, and your comment that "everybody that doing [sic] so is stupid" is directly saying that creating dynamic vectors is stupid. You made an unfounded assumption, and I was unfortunate enough to take your answer seriously. – jstm88 Feb 20 '11 at 20:08
  • @jfm429: Creating `std::vector` instances on the heap _is_ almost always wrong. That's not an assumption, but a well-founded advice. I stand by it. The code in this question is abominable and all it shows is that you know very little about C++. (Had you done as I suggested and researched questions here on SO regarding when to use the stack/heap, you might have learned about that. The first three I tried from the list of questions related to this one all had very excellent answers. But you keep refusing to want to learn and keep trying to prove others wrong instead. Good luck with that.) – sbi Feb 20 '11 at 20:34
  • @jfm429: I just saw that you snipped the quote, thereby severely altering its meaning. I wrote "Nobody said using a dynamic vector will mess up the heap. However, everybody [said] that doing so is stupid." Yes, I forgot the second "said". (It was either a simple typo, or my native language shining through.) But I think the meaning is still obvious, and very different from what your quoting suggests. ICBWT. – sbi Feb 20 '11 at 20:38
  • sbi: Even then, the meaning is still the same: that somehow you can't create vectors on the heap. You still haven't explained how creating vectors on the heap is problematic as long as you manage the memory properly. I could argue that you should never use an array because you might try to access an element that's not there and it might cause an exception, just like you're arguing that you should never use a heap vector because you might not manage the memory properly. And you still haven't explained why you made your initial comment based on an assumption. – jstm88 Feb 20 '11 at 20:50
  • @jmf429: I haven't said that, and what I said I won't (again) explain to you, nor will I explain the underlying reasons for it. The rep you kept referring to I got by answering C++ questions in a way others liked, _in my own time_, because I enjoyed doing so. You, OTOH, have pulled just about every trick in the book to take the joy out of it. So I will rather spend my times playing with the kids, mawing the lawn, reading a book, or whatever I like, than explaining something to someone who doesn't want to learn. I didn't even put up such behavior in students while being _payed_ to teach them. – sbi Feb 20 '11 at 21:25
  • You will most likely see this as an attempt to cover the fact that I don't know what I'm talking about. But that's Ok with me. I'll bow out this moment. Have a nice day. – sbi Feb 20 '11 at 21:26

7 Answers7

9

So, the first question is: if how can I convert the stack object (obj2) to a heap object so it's not deallocated after create() exits? I want a straight answer,

The straight answer is: You can't "convert" an object between the stack and heap. You can create a copy of the object that lives in the other space, as others have pointed out, but that's it.

The second question: the specific example of heap objects being "wrong" was creating a new vector* using the new operator. If dynamically allocating STL objects is wrong, then what's the right way? Obviously if you create them as stack objects it fails because they're immediately deallocated, but I've been told (again, by a very high-ranking member) that dynamically allocating them can corrupt the heap.

Dynamically allocating STL objects will not on its own corrupt the heap. (No idea where you might have heard that.)

If you want to use a stack-allocated STL object outside of the function that you created it in, you can't, since the stack space in which the object resides is only valid inside the function that created it.

You can, however, return a copy of the object:

std::vector<char> SomeFunc()
{
    std::vector<char> myvector;
    // myvector.operations ...
    return myvector;
}

As I said, though, this will return a copy of the object, not the original object itself -- that would be impossible, since the stack that contains the object is unwound after the function returns.

One other option is to have the caller pass in a reference / pointer to the object that your function manipulates, if this makes sense for your particular scenario:

void SomeFunc(std::vector<char>& destination)
{
    // destination.operations ...
}

void AnotherFunc()
{
    std::vector<char> myvector;
    SomeFunc(myvector);
}

As you can see, you've still allocated everything on the stack, and you avoid the (sometimes consequential) overhead of relying on the copy-constructor to return a copy of the object.

Ben M
  • 22,262
  • 3
  • 67
  • 71
  • 3
    Returning copies of an object is a lot cheaper than this answer makes it sound because the compiler can almost always elide the copy. – Konrad Rudolph Feb 20 '11 at 18:33
  • Thank you for finally answering the actual question. I do know about stack/heap objects (which is why I used the example to illustrate why stack objects wouldn't work) but I couldn't find an easy way to convert between them efficiently (without the copy constructor) and use a heap object where a stack object was expected (i.e. using &variable returns a pointer to a stack object within the scope of the function, but I've never been able to get it to work the other way around, like when a function expects a Class& and you want to give it a heap object). If there's a way I'd be glad to hear it... – jstm88 Feb 20 '11 at 18:40
  • If a function expects a `Class &` and you have a `Class * ptr` got from the heap, you can simply dereference the pointer and pass it to the function (e.g. `func(*ptr)`), there's nothing wrong with it. By the way, in general if the function gets a reference the object lifetime management remains on the caller side. – Matteo Italia Feb 20 '11 at 18:47
  • Konrad, are you saying that the compiler won't actually copy it but will shift the actual data in the stack? It still leaves the issues of lots of objects on a deep stack being more likely to cause an overflow, but on the other hand does make a bit more sense in terms of returning copies of objects (I've used memcpy() extensively in some code that processes large amounts of data and I know how fast it can be). I still need the heap objects for my purposes but I'll keep that in mind in the future. – jstm88 Feb 20 '11 at 18:50
  • Matteo, I've tried that and believe it or not with certain systems it does not work. For example, with `void doThis(Class& obj) {}`, if I have `Class *obj1 = new Class();` and then do `doThis(*obj1);`, it works on some systems but not others (i.e. some specific Solaris machines we were dealing with, as well as a few variants of Linux). I'm not sure if it was simply the version of GCC or if that specific usage is an implementation-dependent feature but I've learned not to rely on it because it doesn't work on some of the systems I deal with. – jstm88 Feb 20 '11 at 18:54
  • @jfm429 It will neither copy nor shift the data. It will actually construct the return object directly in the recipient’s memory (read up on the mechanism here: http://msdn.microsoft.com/en-us/library/ms364057%28v=vs.80%29.aspx). Furthermore, there is no danger of a stack overflow whatsoever. For example, the vector only has a small overhead on the stack. The vector elements themselves will be stored on the heap, not on the stack. The vector’s size on the stack doesn’t exceed a few bytes. – Konrad Rudolph Feb 20 '11 at 19:23
  • @Konrad Rudolph, very good point about the return optimization. I knew that was likely, but am not confident enough in C++ to have stated it in my answer. Thanks! – Ben M Feb 20 '11 at 19:31
  • Konrad, that's a compiler-specific feature. Do you know how GCC or Clang handles it? It's apparently in the C++ standard but not all compilers support it the same way. Also, for vectors, yes, they're relatively small on the heap, but there could be other objects that take up much more space, depending on implementation. The differing implementations of copy constructor elision is more likely to be a problem though. – jstm88 Feb 20 '11 at 19:59
  • @jfm429: it's strange, if should work flawlessly, what problems are you experiencing with it? – Matteo Italia Feb 20 '11 at 20:10
  • I always HATED the Return Value Optimization, (http://en.wikipedia.org/wiki/Return_value_optimization) because from the POV of the programmer it isn't "logical". It's an optimization that can (CAN, not WILL) change the result of the program, and its implementation is left to the whim of the compiler. It's like "toss a coin and see the result". There isn't any guarantee it will be used or not. – xanatos Feb 20 '11 at 20:14
  • @xanatos That’s the way optimizations work. Do you hate all other optimizations as well? What’s more, NRVO works very reliably on modern compilers. And if it changes the observable result of the program then **it’s your fault** because the C++ standard explicitly allows this optimization and mandates that the copy constructor doesn’t contain any code that causes the program to change behaviour due to an elided copy. – Konrad Rudolph Feb 20 '11 at 20:17
  • Matteo: it just crashes with a SEGFAULT the next time I try to access the object. I haven't tried it in a while but I think there was a compiler warning (not error) as well. – jstm88 Feb 20 '11 at 20:17
  • @jfm429 All modern compilers support it. MSVC, GCC, clang, ICC probably also Digital Mars. – Konrad Rudolph Feb 20 '11 at 20:18
  • @Konrad No, I only hate optimizations that change my code to produce different results, and this "different" result can't be predicted. There are only a few of these, luckily (plus some implemented in FP math, but often they can be disabled, or are ignorable). In VC 2005 there are some exceptions, so the rule won't always be used (it's even written on the wiki and in the msdn). – xanatos Feb 20 '11 at 20:20
  • Konrad, xanatos: The biggest problem is not behavior change (as Konrad said, if you implement the copy constructor properly it should work fine) but for me the issue is that you don't know it will actually do it. If it doesn't do it you have a performance hit, whereas using other techniques I can make sure it's optimized independent of the compiler. That said, that's only be an issue in certain situations but it could be a problem with deep recursion. – jstm88 Feb 20 '11 at 20:23
  • @xanatos Well, as I said if this optimization changes the observable effect of your program, then only because your code is buggy. The same is true for any other optimization. – Konrad Rudolph Feb 20 '11 at 20:24
  • Also, in some cases you have to remember that consistency is more important than speed; if I have code that runs 10% faster on most systems but runs 90% slower on some, that can sometimes be worse than just having it run consistently on everything, even if it's just a little bit slower. Of course you'd like the faster code on everything but that's sometimes just not the case. – jstm88 Feb 20 '11 at 20:26
  • @Konrad I prefer to think they changed the rules of the game and made my code buggy. Nowhere it's written that copy constructors and destructors shouldn't have side effects, so it's not a bug for them to have. But then they introduce a rule where 1+1=1 or 1+1=2. Yes, you can program AROUND it, but what happens if you wrote your code BEFORE the rule was written? What will happen if next year they take away that rule? It's an option, so it can surely be taken away. I think they should simply have created a retval "implicit" variable and be done with it. Now the future generations will pay. – xanatos Feb 20 '11 at 20:31
  • xanatos: I wonder - is there a flag you can set to disable the optimization? A quick Google search turns up `-fno-elide-constructors` but I haven't tested it. – jstm88 Feb 20 '11 at 20:36
  • @xanatos “I prefer to think they changed the rules of the game and made my code buggy” it’s really irrelevant what you think because you’re wrong. The standard is explicit on the fact that this optimization is legal and by inference your copy constructor call in these circumstances cannot be relied on. Also, it’s been eternities since a “before the rule” and there won’t be an “after the rule”. – Konrad Rudolph Feb 20 '11 at 20:38
  • @konrad Tomorrow they could create a rule like "an object instantiated on the stack that isn't ever accessed (no methods are called, no fields are set by the code in the scope) and that will be destroyed before exiting the scope, and of which there aren't references can not be instantiated even if its constructor and destructor have side effects". Would you like this rule? Would your programs work with this rule? It would we as "legal" as the retvalue optimization. We could call it "the useless object optimization". – xanatos Feb 20 '11 at 20:45
  • xanatos: I've got to (partly) agree with Konrad on this one, and if you had an object like that you would probably want to rethink your design. Of course you may have a legitimate reason to do that, in which case there are (hopefully) compiler flags to turn off. On the other hand, I would hope that in that case the compiler would simply give a warning (as Clang does and I believe GCC as well) that the object is never used, so you can see that it's never used and take appropriate action. I'm in favor of warnings as opposed to errors; it gives the programmer more options... – jstm88 Feb 20 '11 at 20:57
5

So, the first question is: if how can I convert the stack object (obj2) to a heap object so it's not deallocated after create() exits?

This line:

_obj2 = &obj2;

Change to:

_obj2 = new Class(obj2);  // Create an object on the heap invoking the copy constructor.

I want a straight answer, not an arrogant "you're doing it wrong" as so many have done.

Thats as straight an answer as you can get. Obviously you are new to C++, So I am sure this will nto work as intended because you have probably made a couple of mistakes in the defintion of the class "Class" (by the way terrible name).

Also, converting back to a stack object would be useful as well.

class obj3(*_obj2);  // dereference the heap object pass it to the copy constructor.

The second question: the specific example of heap objects being "wrong" was creating a new vector<string>* using the new operator. If dynamically allocating STL objects is wrong, then what's the right way?

Why do you dynamically allocate the vector. Just create it locally.

std::vector<std::string> funct()
{
    std::vector<std::string>   vecString;
    // fill your vector here.

    return vecString;  // Notice no dynamic allocation with new,
}

Using new/delete is using C++ like C. What you need to read up on is smart pointers. These are obejcts that control the lifespan of the object and automatically delete the object when they go out of scope.

std::auto_ptr<Class>   x(new Class);

Here x is a smart pointer (of type auto_ptr) when it goes out of scope the object will be deleted. But you can return an auto_ptr to the calling function and it will be safely transfered out of the function. Its actually a lot more complicated than that and you need a book.

Obviously if you create them as stack objects it fails because they're immediately deallocated,

Its de'allocated when it goes out of scope.

but I've been told (again, by a very high-ranking member) that dynamically allocating them can corrupt the heap.

If you do it incorrectly. Which given your knowledge is very likely. But hard to verify since you have not provided the definition of Class.

So what's the right way to do it?

  1. Learn why you should use stack objects
  2. Learn what smart pointers are.
  3. Learn how to use smart pointers to control lifespans of objects.
  4. Learn the different types of smart pointers.
  5. Look up what the separation of concerns is (you are not following this basic principle).
Martin York
  • 257,169
  • 86
  • 333
  • 562
1

You have to either copy-construct a new heap object (Class * foo = new Class(obj2)) or assign the stack object to a heap object (*obj1 = obj2).

swegi
  • 4,046
  • 1
  • 26
  • 45
  • 1
    Yes, although I would recommend the copy-constructor method over the assignment. Also, if you do the assignment method, you first have to create a new class object, so it takes two steps: `_obj2 = new Class(); *_obj2 = obj2;` - so you can see why I prefer the one-step copy constructor. – Tim Feb 20 '11 at 18:10
0

the only way is to copy object.

Change declaration to:

Class _obj2;

and assign:

_obj2 = obj2;

Andrey
  • 59,039
  • 12
  • 119
  • 163
0

Your stack object is created inside the create function and is deallocated as soon you get out of scope of the function. The pointer is invalid.

You could change Class* obj2 to Class obj2 and the assign (which means copy) the object by obj2 = obj2;

Jim Lewis
  • 43,505
  • 7
  • 82
  • 96
dwo
  • 3,576
  • 2
  • 22
  • 39
  • The heap object remains valid until it is deallocated. Since this program never deletes it, it will remain valid until the program ends. – Ben Voigt Feb 20 '11 at 18:02
  • @Ben: I think dwo probably meant to say "stack" instead of "heap", and I edited accordingly. – Jim Lewis Feb 20 '11 at 18:05
0

Taking the address of a stack variable won't magically transfer it into heap. You need to write a proper copy-constructor for your class and use _obj2 = new Class(obj2);.

As for STL containers, they allocate their data on the heap anyway, why would you want to allocate container itself on the heap? Put them in a scope that will keep them alive as long as you need them.

Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
0

I think you're really trying to ask "How can I return an object created inside my function?" There are several valid ways:

  • Allocate on the heap and return a pointer
  • Use an automatic variable and return its value, not a pointer (the compiler will copy it)
  • Let the caller provide storage, either by pointer or reference parameter, and build your object there.
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720