tags:

views:

172

answers:

9

How to write a getter that can not be deleted? I want to own the variables and not share them. reading here and there I figured out that no matter what I return the memory can be freed

however I define it, is this true?

references, const pointers, no matter what, the function which is calling the getter can delete it and my private variable would not be nullified but with broken memory, right?

I would like to develop a getter where I can return my private variable and be sure that the callee can't delete it...

I am afraid that, while internally using the private variable, the callee has destroyed it and then it crashes away my programm on my internal next attempt to use it

in a first attempt I wouldn't like to use boost, as I am trying to learn the most from this project, boost would be used if not other way around or if the other way around is too complex/much-work

Thanks,

Joe

My other question wasn't really focused so I did it again, its not a problem to asks things here, right? =]

A: 

If you return by value, the caller will not have any access to your internal member.

R Samuel Klatchko
isn't by value just for POD?
Jonathan
No, although it's most common with them. But, for example, iterators and function objects are treated as cheap-to-copy in the std lib and are thus copied a lot. And those aren't PODs.
sbi
No. You can return anything by value. If the data is not POD, it will invoke the copy constructor.
R Samuel Klatchko
Not all classes have accessible copy constructors. Classes with auto_ptr<> can be copied, but it messes up the original.
David Thornley
+4  A: 

Depends on what you mean. Any time you have a pointer, it is possible to call delete on it.

And if you have a reference, you can take the address of it, which gives you a pointer

Anyway, if you have this class for example:

class X {
  int getByVal() { return i; } // returns a copy of i
  int& getByRef() { return i; } // returns a reference to i
private:
  int i;
};

then I, as a user of your class, do not have an obvious way to delete your data. I can do the following:

X x;
int j = x.getByVal();
int& k = x.getByRef();
j = 42; // doesn't affect x.i because we returned a copy
k = 42; // sets x.i to 42, because k is a reference

And there's no obvious way for me to delete the class member. Of course, I could do this:

delete &j;
delete &k;

(and of course, neither of these would do anything meaningful, but they would compile) but I wouldn't do so by accident. If you don't return a pointer, it's pretty clear that I'm not supposed to take ownership of the data.

"Protect your code against Murphy, not Machiavelli" is usually a good rule of thumb. You can't prevent people from wrecking your code if they try. All you should worry about is preventing them from doing it accidentally.

Edit
In response to your comment under the question:

as I said, I am learning... Copies make think that the callee must free the memory of the returning variable, which is more trouble to the callee(even thought it is me =p), so I wasn't talking about concepts, but the easyness of writing... and again, I am newbie on this memory stuff. I was developing in C#, PHP etc. I used to develop in C long time ago when I was learning with CircleMUD

No, copies don't have to be deleted manually. Local variables are automatically deleted when they go out of scope. So in the above example, j is a copy of the class member i. When the calling function returns, j will be automatically deleted.

Hope that helps. The variable lifetime rules in C++ are not very complicated, but it is extremely important to get them right as a lot of code depends on them.

void foo()
{
  int i = 0; // allocate a local (on the stack) int, and initialize it to 0
  int* p = new int(1); // allocate an int on the heap, and initialize it to 1
  int j = i; // create a *copy* of i. Now we have two ints on the stack
  int k = *p; // create a copy of the int pointed to by p. k is also on the stack, so even though it was copied from a heap-allocated variable, k does not have to be manually deleted
  int* q = p; // create a copy of p. q is not a separate pointer, which points to the *same* heap-allocated integer.
}

in the above example, all the copies are automatically cleaned up when foo returns. The only thing we have to do manually is to delete the integer we allocated on the heap. Both p and q point to it, but we must only delete the object once. But i, j, k, p, and q are all local variables, declared on the stack. Each of them are cleaned up when the function returns. For primitive types (such as ints as well as pointers), nothing really has to happen (they don't have destructors). When they go out of scope, they just disappear - even if they pointed to something important, like a heap-allocated object such as our integer.

For non-POD objects, when they go out of scope, their destructors are called, so they too get cleaned up nicely, all by themselves. So even if we'd used a more complex type than int, the above would have worked just fine. We can still copy non-POD objects and pass them by value.

I hope that helps clear things up a bit.

jalf
+1 for the reference to Sutter's "Murphy vs Machiavelli" advice
Éric Malenfant
Is that where it's from? I just know it's a good quote :D
jalf
Well, the first time I saw that expression was in his Exceptional C++ book
Éric Malenfant
"And if you have a reference, you can dereference it " dereferencing is converting a pointer to a reference, not vice versa
bdonlan
@bdonlan: doh, thanks for catching that :)
jalf
There's a GOTW page with the "Murphy vs. Machiavelli" quote here: http://www.gotw.ca/gotw/076.htm.
Fred Larson
thanks, it helped me a lot
Jonathan
+1  A: 

You can use weak pointers for that. Weak pointers refer to a resource owned by a sharing smart pointer without adding to its reference count. (However, as long as users can achieve a naked pointer from a smart pointer - and without that, it would only be smart, but not a pointer anymore -, they can invoke delete on that. But that's OK: If people want to crash their code, they'll always find ways to do this. See your goal in preventing Murphy from doing his work, not Macchiavelli.

Of course, you can just as well return a reference. (The same disclaimer as above applies.)

If your objects are cheap to copy, you can also return a copy. (And it's, syntqactically, still possible to pass the copy's address to delete.)

sbi
Weak pointers are a good solution if pointer semantics are required, but from reading the question I'm not really sure if that's the case. A lot of beginners just tend to use pointers *everywhere*, and then the best answer is simply "don't'". But you know that already :)
jalf
@jalf: _I_ know, but from the accepted answer it looks like your comment was right. `:)`
sbi
+3  A: 

Well, the safest way to do that is to return a copy of your object by value:

MyObject GetMyObject() const {return _myObject;}

Then the caller can do anything he wants with his copy, and it won't affect you.

Of course, that does incur the overhead of copying the object... whether that's important or not depends on how complex the object is (and thus how expensive it is to copy it).

The next best thing is to return a const reference to it:

const MyObject & GetMyObject() const {return _myObject;}

That will give the called a reference to the object, which can technically be deleted but generally won't be (it's assumed that no ownership is passed when returning a reference).

The final thing you could do is use reference counting to return a reference to the object. In that case, nobody ever needs to delete the object, since the object will be automatically deleted when the last reference to it goes away. Check out boost's shared_ptr class for details on this; I highly recommend reference counting as a way of managing memory allocation in C++, since it automates away 99% of the potential errors programmers make when managing memory.

Jeremy Friesner
what? only returning the private variable means I am return a copy??
Jonathan
Yes, that's correct -- returning by value implicitly copies the object that is being returned.
Jeremy Friesner
+3  A: 

In C++, there is nothing you can do to prevent the caller from crashing your program. Period.

I would suggest just returning a reference. If the caller goes and takes the address of that and passes it to delete, they're asking for trouble - and if they're that intent on breaking things, there's not much you can do to stop them.

bdonlan
great answer. I will keep using references... I thought that the const keyword after the () of the funciton would make that return undeletable or sort of that. So it would be better because I am using lots of inheritance and can't use abstract classes with vector if not pointers (or somehow can i? =p)
Jonathan
It's already undeletable, just like delete is undeletable - that is, if you delete it, things break, badly :) All you have to do to get the same magic is to declare in your documentation "THOU SHALT NOT DELETE THIS STUFF" and avoid actually returning pointers unless necessary. And hope the user has an ounce of common sense :)
bdonlan
A: 

A really ad hoc solution might be to overload operator new and delete (and perhaps new[]/delete[]), making the delete operator private and granting access only to the owner class:

#include <memory>

class Y
{
private:
    void* operator new(size_t size) { return new char[size]; }
    void operator delete(void* p) { delete [] static_cast<char*>(p); }
    friend class X;
};

class X
{
    Y* p;
    X(const X& x);
    const X& operator=(const X& x);
public:
    X(): p(new Y()) {}
    ~X() { 
        delete p;  //OK here, X is a friend
    }
    const Y* get() const { return p; }
};

int main()
{
    X x;
    const Y* p = x.get();
    delete p;  //error here: operator delete is private
}

However, as long as you don't return a naked pointer where a mistake might be imaginable, if you were to return a smart pointer, and the caller still decided to free the managed pointer, everything that ensues will be their problem. Pretty much any time you see a call to delete, you'd know it must be an error.

UncleBens
heh, now that's the paranoid solution ;)
jalf
Jonathan
It is verbatim what OP asked for :) Not something I'd particularly recommend.
UncleBens
UncleBens
A: 

Have you thought about finding people who write code that deletes other module's variables, and spray-painting them puce or something like that?

Seriously, if your colleagues are absolutely determined to break things, there's really not much you can do about it (except fire them on the spot, if you're the boss). Heck, there's no guarantee that what you're passing out is something that was separately allocated, and if the caller uses delete on a random address there's no telling what will happen (except that some form of heap corruption is almost certain).

There's no programming language construct, or programming language for that matter, which will save you from colleagues like that. "Against stupidity the gods themselves contend in vain."

David Thornley
calm down, take it easy... I am learning. If you think that a second class can't access private members of first class, why can't there be a keyword that tells the compiler to not be able to delete it ouside the class or sort of that? sincerely, all those const as prefix, sufix and midlefix O_o... I thought one would be like this.
Jonathan
This is so not a technical problem. The keyword you want is of course const, but you ruled that out in the question, presumably because some idiot could use const_cast<>() on it and delete it anyway, even if it can't be deleted. If "const foo *" doesn't work, it's because it's being deliberately subverted, and that's a people problem.
David Thornley
@David: You can `delete` a pointer-to-const. No cast required.
Troubadour
A: 

If you have an object that takes ownership (A bank takes an account (contrived I know)).
But people want access to the account but you dont want them to delete it.

class Bank
{
    public:
        // use auto_ptr to indicate transfer of ownership to the Bank.
        void addAccount(std::auto_ptr<Account> a)
        {
            m_account = a;
        }
        //
        // getAccount() returns a reference to the object
        // Anbody using the object can NOT now delete it.
        // But they can manipulate it.
        Account&  getAccount(int accountNo)
        {
            return *m_account;
        }
    private:
        std::shared_ptr<Account>   m_account;  // In example bank only has 1 account
}
Martin York
A: 

I'm not sure if this is what you are looking for and it also depends on how much effort you really need to take but you could always use the pimpl idiom.

Wrap up the member you don't want to expose and just pass out handles to it. The handles are just lightweight wrappers that can be merrily passed around by value, each handle simply points at the same underlying unique piece of data which only your internal code can actually create and destroy.

For example,

class Interface
{
public:
    Data getData() const { return Data( m_data ); }

private:
    DataImpl* m_data;
};

where

class Data
{
public:
    // Just use compiler-synthesised copy ctor, assignment and dtor

    // Declare as many forwarding methods to impl as required
    // ...

private:
    friend class Interface;
    Data( DataImpl* d ) : m_impl( d ) {}
    DataImpl*const m_impl;
};

The simple example here is naive since it does not invalidate any existing Data handles when the DataImpl is ultimately destroyed and so they are left with stale pointers. This can be solved with more effort but again you're left with the question of whether it's really worth it.

Troubadour