Overloading bracket assignment in C++ - c++

I am in the process of porting an Objective-C application to C++ and I decided to create a class similar to NSObject and NSDictionary. If you are unfamiliar with this system, an NSObject is an object which all objects inherit form in Obj-C and then there is a reference counting mechanism within it. When there are no more references, the object frees itself.
In my code, I would like to be able to do the following
CMDictionary["Key"] = Object;
Internally, this is stored as
Map<string, CMObject*> mDictionary
Whenever a new object is assigned into the object, the dictionary must then retain this object by calling its retain function as well as calling release on any object that this new object might have replaced. My problem stems from the fact that I cannot find anyway to run code and determine when the brackets are being used in an assignment as I would not want the retain function to be called when I wrote something like
CMDicionary["key"]->StringValue();
Would there by anyway to do this, or would I need to just use getter/setter functions to modify my dictionary

What you typically do in this situation is to implement:
Object const& Map::operator[](string) const;
Object& Map::operator[](string);
Note that I wrote Object& instead of Object. You can at any rate instantiate a new Object and hand it out, relying on a proper Object& Object::operator=(Object const&) to be implemented, which will then perform the assignment, after your Map::operator[] function returns (don't worry, the compiler will optimise it away in most cases).

You should overload the operator[] to accept a string.
http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html

Consider writing a new class similar to shared_ptr<CMObject*> and do the retain/release inside of that object.

Related

C++ Set object member as reference/pointer of member of a different object?

(I'm not sure if that title is worded correctly, as I'm still new to C++)
I have two classes, loosely represented here:
class SuperGroup
{
public:
LayoutObj theLayout;
}
class SomeClass
{
public:
LayoutObj myLayout;
SuperGroup myGroup;
}
During SomeClass's constructor, I want to set myGroup.theLayout to be pointing to SomeClass's searchLayout. Something like this:
SomeClass::SomeClass()
{
myGroup.theLayout = &myLayout;
}
Am I doing this correctly? Or do I need to be using a pointer? My code seems to compile okay, but when I execute it, it crashes, and I can tell its something to do with this assignment. Also, I'm not sure if its incorrectly coded, or if the SDK/API I'm using simply doesn't like it.
The reason I'm trying to reference myLayout with SuperGroup is because I have many methods in SuperGroup that need to use myLayout from SomeClass. I'm simply trying to avoid having the pass myLayout by reference into those methods every single time. Make sense? Is there an easier way to accomplish this?
You do indeed need a pointer. Try using:
LayoutObj *theLayout;
Without a pointer, you are trying to assign a LayoutObj to a memory address. This may compile, but is not the behavior you want. Instead, you need a pointer to point to the memory address of a LayoutObj.
The line myGroup.theLayout = &myLayout; remains the same.
As always is the case with C++, be careful that myLayout does not go out of scope before theLayout. If this happens, you have a dangling pointer. If there is any risk of this, consider using a smart pointer of some kind, or otherwise modify your design to accommodate this.
Yes, you would need to use a pointer: LayoutObj *theLayout;
In reference to your last paragraph, I would consider the some alternative designs, such as:
Requiring that the LayoutObj is passed into each method of SuperGroup, therefore decoupling the particular LayoutObj acted upon from the actions that can be performed, or
Moving those methods to SomeClass, if they're not needed elsewhere, or
Making them methods of LayoutObj itself.

private object pointer vs object value, and returning object internals

Related to: C++ private pointer "leaking"?
According to Effective C++ (Item 28), "avoid returning handles (references, pointers, or iterators) to object internals. It increases encapsulation, helps const member functions act const, and minimizes the creation of dangling handles."
Returning objects by value is the only way I can think of to avoid returning handles. This to me suggests I should return private object internals by value as much as possible.
However, to return object by value, this requires the copy constructor which goes against the Google C++ Style Guide of "DISALLOW_COPY_AND_ASSIGN" operators.
As a C++ newbie, unless I am missing something, I find these two suggestions to conflict each other.
So my questions are: is there no silver bullet which allows efficient reference returns to object internals that aren't susceptible to dangling pointers? Is the const reference return as good as it gets? In addition, should I not be using pointers for private object fields that often? What is a general rule of thumb for choosing when to store private instance fields of objects as by value or by pointer?
(Edit) For clarification, Meyers' example dangling pointer code:
class Rectangle {
public:
const Point& upperLeft() const { return pData->ulhc; }
const Point& lowerRight() const { return pData->lrhc; }
...
};
class GUIObject { ... };
const Rectangle boundingBox(const GUIObject& obj);
If the client creates a function with code such as:
GUIObject *pgo; // point to some GUIObject
const Point *pUpperLeft = &(boundingBox(*pgo).upperLeft());
"The call to boundingBox will return a new, temporary Rectangle object [(called temp from here.)] upperLeft will then be called on temp, and that call will return a reference to an internal part of temp, in particular, to one of the Points making it up...at the end of the statement, boundingBox's return value temp will be destroyed, and that will indirectly lead to the destruction of temp's Points. That, in turn, will leave pUpperLeft pointing to an object that no longer exists." Meyers, Effective C++ (Item 28)
I think he is suggesting to return Point by value instead to avoid this:
const Point upperLeft() const { return pData->ulhc; }
The Google C++ style guide is, shall we say, somewhat "special" and has led to much discussion on various C++ newsgroups. Let's leave it at that.
Under normal circumstances I would suggest that following the guidelines in Effective C++ is generally considered to be a good thing; in your specific case, returning an object instead of any sort of reference to an internal object is usually the right thing to do. Most compilers are pretty good at handling large return values (Google for Return Value Optimization, pretty much every compiler does it).
If measurements with a profiler suggest that returning a value is becoming a bottleneck, then I would look at alternative methods.
First, let's look at this statement in context:
According to Effective C++ (Item 28),
"avoid returning handles (references,
pointers, or iterators) to object
internals. It increases encapsulation,
helps const member functions act
const, and minimizes the creation of
dangling handles."
This is basically talking about a class's ability to maintain invariants (properties that remain unchanged, roughly speaking).
Let's say you have a button widget wrapper, Button, which stores an OS-specific window handle to the button. If the client using the class had access to the internal handle, they could tamper with it using OS-specific calls like destroying the button, making it invisible, etc. Basically by returning this handle, your Button class sacrifices any control it originally had over the button handle.
You want to avoid these situations in such a Button class by providing everything you can do with the button as methods in this Button class. Then you don't need to ever return a handle to the OS-specific button handle.
Unfortunately, this doesn't always work in practice. Sometimes you have to return the handle or pointer or some other internal by reference for various reasons. Let's take boost::scoped_ptr, for instance. It is a smart pointer designed to manage memory through the internal pointer it stores. It has a get() method which returns this internal pointer. Unfortunately, that allows clients to do things like:
delete my_scoped_ptr.get(); // wrong
Nevertheless, this compromise was required because there are many cases where we are working with C/C++ APIs that require regular pointers to be passed in. Compromises are often necessary to satisfy libraries which don't accept your particular class but does accept one of its internals.
In your case, try to think if your class can avoid returning internals this way by instead providing functions to do everything one would want to do with the internal through your public interface. If not, then you've done all you can do; you'll have to return a pointer/reference to it but it would be a good habit to document it as a special case. You should also consider using friends if you know which places need to gain access to the class's internals in advance; this way you can keep such accessor methods private and inaccessible to everyone else.
Returning objects by value is the only
way I can think of to avoid returning
handles. This to me suggests I should
return private object internals by
value as much as possible.
No, if you can return a copy, then you can equally return by const reference. The clients cannot (under normal circumstances) tamper with such internals.
It really depends on the situation. If you plan to see changes in the calling method you want to pass by reference. Remember that passing by value is a pretty heavy operation. It requires a call to the copy constructor which in essence has to allocate and store enough memory to fit size of your object.
One thing you can do is fake pass by value. What that means is pass the actual parameter by value to a method that accepts const your object. This of course means the caller does not care to see changes to your object.
Try to limit pass by value if you can unless you have to.

Create an instance from a static method

let's say I want my users to use only one class, say SpecialData.
Now, this data class would have many methods, and depending on the type of data, the methods do different things, internally, but return externally similar results. Therefore my wanting to have one "public" class and other "private", child classes that would change the behavior of methods, etc...
It would be amazingly more simple for some types of data that need to be built to do something like this:
SpecialData& sm = SpecialData::new_supermatrix();
and new_supermatrix() would return a SuperMatrix instance, which inherits from most behaviors of SpecialData.
my header:
static SpecialData& new_supermatrix();
my cpp:
SpecialData& SpecialData::new_supermatrix()(){
return SuperMatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...);
}
The problem is, I get this error, which is probably logical due to the circumstances:
invalid initialization of non-const reference of type ‘SpecialData&’ from a temporary of type ‘SpecialData’
So, any ideas?
Well, you've got three choices:
a) You want to have only one instance of SuperMatrix anyway. Then go for the static function member route as has already been suggested.
b) You want to create multiple instances. Then you have to return a pointer instead of references and create the objects with with new (i.e. return new SuperMatrix(...).
c) As an alternative to option b, you can also return merely an object, i.e.
SpecialData SpecialData::new_supermatrix()(){
return SuperMatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...);
}
However, this requires a (deep-)copy operator (the default one won't suffice more often than not), and it means that the object is created on the stack, then copied and that copy is being returned. The good thing is, this won't leak memory if you don't actually receive the result into a variable. The bad thing is, if the object is very large, this can be very memory- and time-consuming.
Whatever you are going to do with it, these solutions are mutually exclusive, both technically and logically. ;)
Simple answer - you can't use references like that. Your new_supermatrix function returns a nameless temporary value which you try to bind to a non-const reference - C++ only allows such values to be bound to const references. If you want to write functions like this, you need to make them return a pointer to a dynamically allocated object, or stick with returning a value, but assign the return value to another value in the calling code.
This code has several problems. First of all, you probably want to use pointers here instead of references. Returning a reference to an object created on the stack like you do in your new_supermatrix will lead to a crash almost immediately. It needs to be allocated with new and passed back as a pointer if that's what you want but I'm not exactly sure what you're trying to do. But anyway, this is what's causing your error, you're returning a reference to a temporary variable.
You need to actually use the new operator. The creation you get by return SuperMatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...); allocates the object on the stack, which is cleaned up when the function returns (which it is doing in the same line). Using new causes it to be allocated on the heap.
In your method, you can use a static:
SpecialData& SpecialData::new_supermatrix()(){
static SuperMatrix supermatrix(MATRIX_DEFAULT_MAGNITUDE,1000,1239,FLOAT32,etc...);
return supermatrix;
}
You must not return a reference to a temporary/local object.
This and many other common errors-to-be-avoided are explained in Meyers' book, Effective C++.
You're returning a reference to a temporary object, which is bad news, since once your method exits, the object doesn't exist anymore.
Read up on creational design patterns. The one that looks closest to what you want to do is the Factory Method pattern.

Implement Register/Unregister-Pattern in C++

I often come accross the problem that I have a class that has a pair of Register/Unregister-kind-of-methods. e.g.:
class Log {
public:
void AddSink( ostream & Sink );
void RemoveSink( ostream & Sink );
};
This applies to several different cases, like the Observer pattern or related stuff. My concern is, how safe is that? From a previous question I know, that I cannot safely derive object identity from that reference. This approach returns an iterator to the caller, that they have to pass to the unregister method, but this exposes implementation details (the iterator type), so I don't like it. I could return an integer handle, but that would require a lot of extra internal managment (what is the smallest free handle?). How do you go about this?
You are safe unless the client object has two derivations of ostream without using virtual inheritance.
In short, that is the fault of the user -- they should not be multiply inheriting an interface class twice in two different ways.
Use the address and be done with it. In these cases, I take a pointer argument rather than a reference to make it explicit that I will store the address. It also prevents implicit conversions that might kick in if you decided to take a const reference.
class Log {
public:
void AddSink( ostream* Sink );
void RemoveSink( ostream* Sink );
};
You can create an RAII object that calls AddSink in the constructor, and RemoveSink in the destructor to make this pattern exception-safe.
You could manage your objects using smart pointers and compare the pointers for equality inside your register / deregister functions.
If you only have stack allocated objects that are never copied between an register and deregister call you could also pass a pointer instead of the reference.
You could also do:
typedef iterator handle_t;
and hide the fact that your giving out internal iterators if exposing internal data structures worries you.
In your previous question, Konrad Rudolph posted an answer (that you did not accept but has the highest score), saying that everything should be fine if you use base class pointers, which you appear to do.

Deleting a Shared Pointer

I have a pointer to a QScriptEngine that I'm passing through the overloaded class constructor of class Evaluator and assigns it to QScriptEngine *engine_ (class Property subclasses Evaluator, and calls this constructor of Evaluator, passing it an already allocated QScriptEngine). The constructor with no arguments creates the new QScriptEngine pointer (class Generic subclasses Evaluator in this way). In the destructor I test if engine_ is not NULL, delete the pointer, then assign it NULL. Should the pointer (engine_) in the derived Property now also be NULL? Something tells me this is not the case. If not, how do you deal with this situation? I need the QScriptEngine to be the same instance throughout. QScriptEngine's = operator is private, or I would be avoiding the pointer all together.
I saw some info on shared pointers (boost::shared_ptr and std:tr1::shared_ptr) in another SO question. I'm already using boost for the regex library, so boost is not out of the question if that's the best way to deal with this. Hopefully there's a non-boost way, for general C++ knowledge and future projects.
You can solve this by giving one of the classes (class A) lifetime control of that pointer, along with a 'getter' method. The other class (class B) would always call A's getter whenever it needed the pointer. That way, A remains in control of the pointer at all times. Downside is the getter function (it will probably inline, but it's still a second indirection). Also, B is going to have to check that pointer for NULL on pretty much every use.
Your other choice is to wrap the pointer in something like boost::shared_ptr which takes care of the problem (if used properly) by holding the underlying pointer, and only deleting it when all objects that share that pointer are deleted. You could write this yourself, but since you already have boost in play, I'd just use their implementation.
A third choice is to re-factor the whole thing so that you don't need a shared pointer. I'd personally never design a C++ program that needed shared pointers, just because it's a spot where memory management bugs could easily creep in over the years, but that's just me.