tags:

views:

73

answers:

4

I use boost shared_ptr to wrap a pointer. However I can only get the correct value in test_shared_ptr(), while in main(), I get the wrong value.

Expected output:
100
100

Actual output:
100
-572662307

It seems that the pointer becomes invalid in that case. Any correct approach to do the job? Thanks in advance.

Below is the source code.

#include <memory>
#include <iostream>


class TestClass
{
public:
    TestClass(int &i);
    void print_i();
private:
    int *_i;
};

TestClass::TestClass(int &i) : _i(&i)
{

}

void TestClass::print_i()
{
    std::cout << *_i << std::endl;
}


void print_i(int &i)
{
    std::cout << i << std::endl;
}

TestClass *test_shared_ptr()
{
    std::tr1::shared_ptr<int> i(new int());

    *i = 100;

    print_i(*i); 

    return new TestClass(*i);
}


int main(int argc, char** argv)
{
    TestClass *p = test_shared_ptr();
    p->print_i();
    return 0;
}
+2  A: 

It seems that the pointer becomes invalid in that case

Of course it becomes invalid. shared_ptr gets deleted when you leave test_shared_ptr, and i does not exist after that.

Any correct approach to do the job?

1) simply copy value of i. (use int i instead of int* i in TestClass). int is small, you won't lose anything.

or

2) use std::tr1::shared_ptr<int> instead of int* in TestClass.

SigTerm
shared_ptr *is* boost's smart pointer class - tr1 took the design from boost, so it should work exactly the same...
BlueRaja - Danny Pflughoeft
Hi, thanks for your prompt response. Actually I want to pass object by reference instead of generic type in my application. Any suggestions for the smart pointer?
Bowen
@BlueRaja - Danny Pflughoeft: Confused it with auto_ptr. Fixed that already.
SigTerm
+6  A: 

You need to pass around the shared pointer, rather than references and pointers directly to the int.

What's happening is the shared pointer is never passed anywhere outside the test_shared_ptr() function. When that function returns, the shared pointer is destroyed. When it sees that nothing else has a reference to it's memory, it destroys the memory it was pointing at.

Basically, where you are using int &i and int *i change both to use std::tr1::shared_ptr<int> i.

You probably need to read up on shared pointer a bit more. Basically, they keep a reference count for the pointer they are pointing to. When they are copied, they up the reference count, and when they are destroyed the decrement it. When the reference count reaches 0 (nothing else is referencing the memory it is pointing at) it frees that memory. So, even though something is using that pointer in your case, because it did not use a shared pointer there is no way for the shared pointer to know that the memory is still being used, so it frees it.

SoapBox
Hi, thanks for your comments. I don't want to use shared pointer to pass variable values in TestClass's constructor, since I don't want to force the api user to use smart pointer. Maybe smart pointer is not a good option in this case.
Bowen
A: 

What you are doing really breaks the point of shared_ptr. Basically when you pass it out of that function is it magically supposed to break and, thus, not free the pointed too memory?

No. It frees it. Are you expecting the shared_ptr to still exist outside of the function so that when "p" drops out of scope it manages to call teh shared_ptr destructor? This can't happen. p is a pointer not a shared_ptr class.

Either return a shared_ptr or return the new'd pointer and delete it yourself.

Goz
I just tried to create a similar scenario in my real app. In my app, I have a class like TestClass and receives a reference in its constructor. As in test_shared_ptr(), I need to pass a local variable to TestClass (it should not have the reponsibility to release the local variable, say pointer here) and visit it out of scope. I cannot also decide when to delete the pointer since the TestClass need to use it elsewhere.
Bowen
+1  A: 

The issue you are having is with your API contract.

I don't want to use shared pointer to pass variable values in TestClass's constructor, since I don't want to force the api user to use smart pointer

Your TestClass contract is currently looking like you want the caller to maintain the int item so that it has a lifetime longer than TestClass.

Your test case doesn't follow this contract rule however.

Actually I want to pass object by reference instead of generic type in my application.

Passing by reference or by pointer does not have anything to do with 'generic' type.

Here is a possible fix for your code testing your API, the scope of your int is then longer then sufficiently long (untill the end of the app) to handle all usages within TestClass

TestClass *test_shared_ptr(int &i)
{
    i = 100;

    print_i(i); 

    return new TestClass(i);
}


int main(int argc, char** argv)
{
    std::tr1::shared_ptr<int> i(new int());

    TestClass *p = test_shared_ptr(*i);
    p->print_i();
    return 0;
}
Greg Domjan