I have a C++ object exposed to QML with a "sort of" read-only property, except that the property still needs to be set from QML, so it has a WRITE method defined, but other than the initial mandatory setting it never changes, so I feel like a NOTIFY is redundant, as it will already have that value set at the time of its usage, and it will never change.
However, QML doesn't share my feeling, and regardless it spews out a "Expression depends on non-NOTIFYable properties" warning.
Due to the way objects are instantiated using a property is the only applicable way of setting that value, it is not possible to use an invokable setter as such would require the object to already be "completed" and it cannot really complete without that value. Thus the need of the property mechanism and a WRITE method, which unfortunately leads Qt to believe that the property will change. I tried setting the property as CONSTANT but that doesn't seem to stack with having a WRITE method.
I've put a dummy signal as a temporary measure to deal with the flood of warnings, but I'd prefer if there was a more elegant way to deal with this. Again, the very design practically eliminates the possibility of setting this value after its initial setting, but since it is a C++ object and the value needs to be set on a per-object basis, it is not applicable to use a QML readonly property either. Is there a work-around for this that doesn't involve the redundant signal?
Just to clarify, the underlying problem here is that in its current state, QML has pretty much no way to initialize a read only property of an object, implemented in C++. Such a property wouldn't have a setter (if it would then it would spew the "depends on..." warning), and there is no way to pass a value to the object's constructor. As described in my answer below, there are hacks around this, but they are either limited in application or rather inconvenient. In C++ you can do even initialization of const members on a per-instance basis by passing the value to the constructor which does the initialization in the initializer list, but not in QML. Even in pure QML, read only properties must be initialized on the spot, it is not possible to leave them uninitialized (readonly property type name without : statement) and delay that until the instantiation and get per-instance initialization (Obj { name : initValue }). You could do this:
Item { // T.qml
readonly property int r : w
property int w
}
...
T { w: value }
but it... kind of defeats the purpose... And considering that a property can be "bound" only once in the body of its instantiation, I think this could be seen as an act of initialization, while further assignment or imperative rebinding (Qt.binding()) is prohibited. A setter without the redundant notification signal would do the trick, however qtquick's implementation design assumes that if it has a setter it will be changing, thus will complain that it doesn't have a notify signal, which IMO is a design oversight - that is, not providing any way to initialize a read only property on the QML side on per-instance basis. And currently, as I already mentioned, the 3 possible solutions come either with overheads (have a notify signal), limitations (set value before object creation - only applicable for dynamic instantiation) or major inconveniences (use setter and getter slots without implementing the actual property interface).
It depends a bit on what you need the value for.
If the property is used in any property binding then you will need the notification, otherwise you end up in a situtation where you rely on the order of object instantiations and binding evaluations.
E.g. if it is used in a binding elsewhere without having an associated notification signal, then you rely on the initial setting happending before any such binding is evaluated for the first time.
If, on the other hand, the value is only used to initialize the C++ side but never used in QML elsewhere, you could consider using a "setter" function/slot.
One possible solution is to only have a setter and getter functions exposed to QML, but without the actual property. It is a little less elegant and more verbose (an extra ()), but at least it deals with the warning spam in the console. It will probably end up more efficient, since aside from eliminating the redundant signal, there might be less binding expression reevaluation watchers instantiated.
There is also another way, but it only works for creating objects dynamically - it will not work if you create the objects declaratively. This approach involves calling a function before each and every object creation, that function sets a static member value, which the constructor of the object uses as an implicit parameter to initialize the read only property. Thus it becomes obvious why this can only work for objects that are created dynamically, in the other case you don't get to call the function and set the value before the constructor of the object is invoked.
There are also some stock APIs that seem to come with properties that do not have notification either. For example FolderListModel's rootFolder property, and so it generates warnings every time it is used in a binding. The solution to remove those is to use an additional proxy property and bind the FolderListModel property to it.
Related
I've read quite a few discussions that const_cast in C++ is considered wrong and dangerous and should not be used for anything other than backward compatibility with C code. And I generally agree.
However recently I came across the following use case and it made me wonder.
I have some model object, owned by a controller, that is generally non-const. I pass it to a view that should not be able to modify the model object, so it would be logical to declare the object as a const parameter when passed to the view. However the view also makes delegate callbacks to the controller, passing the model object as a parameter (e.g. the user clicked this object). The callback parameter also must be const. In the callback method, the controller wants to make a change to the model, but the model is const so it can't do it.
The two solutions:
use const_cast in the controller's callback method, since it knows the model object is non-const - but it smells.
don't declare the model as const parameter when passed to the view - but then I can't use such a useful tool as the const declaration, which seems very relevant in this case.
Thoughts?
There are two ways to deal with const.
Things are const if this code won't directly change them.
Things are const if this code won't change them.
In this case, the view won't directly change the object. But you want it to indirectly change the object.
Under (2), this means the object isn't const. The view can change the object, if indirectly. It can cause the object to be changed. Saying it is const implies that the views interaction with the object is purely "reading state", not changing the state -- but clicking on the "delete" button of the object and making it delete is a mutating operation.
Under (1), your reference should be const, because you aren't yourself modifying it. Someone else is, under authority granted by their right to do it.
This is one conflict. And (1) is an acceptable way to use const. But when using (1) you should have an alternative route to the object as non-const.
We can see this under vector.erase. It (now) takes const_iterators. Even though those iterators themselves are not permitted to modify the vector, the non-constness of *this provides an alternative access path that permits modification.
In your case, the controller owns the object, so should have a non-const access path to that object. That is the path you should use to do non-const modification of the object.
When the view makes a delegate callback, it might pass an identifier instead of an object -- or, the controller might extract the identifier from the object somehow, and look it back up in its own list of objects.
This is not a good case for const_cast. If the view
accepts the model as a const then it can be given a truly const instance of model. It would then be incorrect to try to pass that instance to the controller. If the reference to the model given to the view can be used to modify the model, then it must not be const.
i was wondering if parametrized constructor should always have only parameters that actually initialize class' attributes. For example, in calling:
Texture background("C:\Documents\Images\background.png");
What if i don't need to store the file path?
An object constructor takes whatever parameters are necessary for returning a valid and functional object. You may allow constructors with extra parameters for syntax sugar, but at the very least, your object should be a valid one. In your case, I don't think a texture makes sense without a file used as texture, so I think removing that parameter is not recommended.
Keep in mind though that you should also aim for making your code easy to test. In that case, complex constructors can be a pain when you want to instantiate an object for testing specif methods. In the end, it is more of a decision process.
If you don't need to store the path, then don't pass it to the constructor! :)
Parametrized constructors are intended to ensure that all information is available when the object is instanciated. So pass only the information that is neccessary.
If you want to follow the RAII idiom, then pass all requered resource to the constructor and release the resources (if the object locks them, like a file or a port).
I don't think there's anything wrong with accepting a parameter which isn't directly stored in the class. Obviously if it doesn't affect the class at all, then that's just a waste of time, but you might accept something like a PRNG seed which you use to fill your class with randomised state, and have no reason to retain the seed beyond that point.
However, passing in a file path which you mean to access within the constructor is dangerous, as there could be any number of problems that come up during that process. You really don't want trouble like that in your constructor.
In avoiding potential failure cases in your constructor you end deferring things like file access until after construction. Consequently the constructor really doesn't need the information because it makes more sense to pass it to the method you use to access the file where you can handle errors more easily.
So, I've been doing some library development and came to a dilemma. Library is private, so I can't share it, but I feel this could be a meaningful question.
The dilemma presented itself as an issue over why there is no default constructor for a resource handling class in the library. The class handles a specific file structure, which is not really important, but lets call the class Quake3File.
The request was then to implement a default constructor and the "appropriate" Open/Close methods. My line of thinking is RAII style, that is if you create a instantiation of the class you must give it a resource that it handles. Doing this ensures that any and all successfully constructed handles are valid and IMO eliminates a whole class of bugs.
My suggestion was to keep a (smart)pointer around and then instead of having to implement a Open/Close and open a can of worms, the user creates the class on the free store to "Open" it and deletes is when you want to "Close" it. Using a smart pointer will even "Close" it for you when it gets out of scope.
This is where the conflict comes in, I like to mimic the STL design of classes, since that makes my classes easier to use. Since I'm making a class that essentially deals with files and if I take std::fstream as a guide, then I am not sure if I should implement a default constructor. The fact that the entire std::fstream hierarchy does it points me to a Yes, but my own thinking goes to No.
So the questions are more or less:
Should resource handles really have default constructors?
What is a good way implement a default constructor on a class that deals with files? Just set the internal state to an invalid one and if a user missuses it by not giving it a resource have it result in undefined behavior? Seems strange to want to take it down this route.
Why does the STL implement the fstream hierarchy with default constructors? Legacy reasons?
Hope my question is understood. Thanks.
One could say that there are two categories of RAII classes: "always valid" and "maybe empty" classes. Most classes in standard libraries (or near-standard libraries like Boost) are of the latter category, for a couple of reasons that I'll explain here. By "always valid", I mean classes that must be constructed into a valid state, and then remain valid until destruction. And by "maybe empty", I mean classes that could be constructed in an invalid (or empty) state, or become invalid (or empty) at some point. In both cases, the RAII principles remain, i.e., the class handles the resource and implements an automatic management of it, as in, it releases the resource upon destruction. So, from a user's perspective, they both enjoy the same protections against leaking resources. But there are some key differences.
First thing to consider is that one key aspect of almost any resource that I can think of is that resource acquisition can always fail. For example, you could fail to open a file, fail to allocate memory, fail to establish a connection, fail to create a context for the resource, etc.. So, you need a method to handle this potential failure. In an "always valid" RAII class, you have no choice but to report that failure by throwing an exception from the constructor. In a "maybe empty" class, you can choose to report that failure either through leaving the object in an empty state, or you can throw an exception. This is probably one of the main reasons why the IO-streams library uses that pattern, because they decided to make exception-throwing an optional feature in its classes (probably because of many people's reticence to using exceptions too much).
Second thing to consider is that "always valid" classes cannot be movable classes. Moving a resource from one object to another implies making the source object "empty". This means that an "always valid" class will have to be non-copyable and non-movable, which could be a bit of an annoyance for the users, and could also limit your own ability to provide an easy-to-use interface (e.g., factory functions, etc.). This will also require the user to allocate the object on freestore whenever he needs to move the object around.
(EDIT)
As pointed out by DyP below, you could have an "always valid" class that is movable, as long as you can put the object in a destructible state. In other words, any other subsequent use of the object would be UB, only destruction will be well-behaved. It remains, however, that a class that enforces an "always valid" resource will be less flexible and cause some annoyance for the user.
(END EDIT)
Obviously, as you pointed out, an "always valid" class will be, in general, more fool-proof in its implementation because you don't need to consider the case where the resource is empty. In other words, when you implement a "maybe empty" class you have to check, within each member function, if the resource is valid (e.g., if the file is open). But remember that "ease of implementation" is not a valid reason to dictate a particular choice of interface, the interface faces the user. But, this problem is also true for code on the user's side. When the user deals with a "maybe empty" object, he always has to check validity, and that can become troublesome and error-prone.
On the other hand, an "always valid" class will have to rely solely on exception mechanisms to report its errors (i.e., error conditions don't disappear because of the postulate of "always valid"), and thus can present some interesting challenges in its implementation. In general, you will have to have strong exception safety guarantees for all your functions involving that class, including both implementation code and user-side code. For example, if you postulate that the object is "always valid", and you attempt an operation that fails (like reading beyond the end of a file), then you need to roll back that operation and bring the object back to its original valid state, to enforce your "always valid" postulate. The user will, in general, be forced to do the same when relevant. This may or may not be compatible with the kind of resource you are dealing with.
(EDIT)
As pointed out by DyP below, there are shades of grey between those two types of RAII classes. So, please note that this explanation is describing two pole-opposites or two general classifications. I am not saying that this is a black-and-white distinction. Obviously, many resources have varying degrees of "validity" (e.g., an invalid file-handler could be in a "not opened" state or a "reached end-of-file" state, which could be handled differently, i.e., like a "always opened", "maybe at EOF", file-handler class).
(END EDIT)
Should resource handles really have default constructors?
Default constructors for RAII classes are generally understood as creating the object into an "empty" state, meaning that they are only valid for "maybe empty" implementations.
What is a good way implement a default constructor on a class that deals with files? Just set the internal state to an invalid one and if a user missuses it by not giving it a resource have it result in undefined behavior? Seems strange to want to take it down this route.
Most resources that I have ever encountered have a natural way to express "emptiness" or "invalidity", whether it be a null pointer, null file-handle, or just a flag to mark the state as being valid or not. So, that's easy. However, this does not mean that a misuse of the class should trigger "undefined behavior". It would be absolutely terrible to design a class like that. As I said earlier, there are error conditions that can occur, and making the class "always valid" does not change that fact, only the means by which you deal with them. In both cases, you must check for error conditions and report them, and fully specify the behavior of your class in case they happen. You cannot just say "if something goes wrong, the code has 'undefined behavior'", you must specify the behavior of your class (one way or another) in case of error conditions, period.
Why does the STL implement the fstream hierarchy with default constructors? Legacy reasons?
First, the IO-stream library is not part of the STL (Standard Template Library), but that's a common mistake. Anyway, if you read my explanations above you will probably understand why the IO-stream library chose to do things the way it does. I think that it essentially boils down to avoiding exceptions as a required, fundamental mechanism for their implementations. They allow exceptions as an option, but don't make them mandatory, and I think that must have been a requirement for many people, especially back in the days it was written, and probably still today.
I think that each case should be considered separately, but for a file class I'd certainly consider the introduction of an "invalid state" like "file cannot be opened" (or "no file attached to the wrapper handler class").
For example, if you don't have this "invalid file" state, you will force a file loading method or function to throw exceptions for the case that a file cannot be opened. I don't like that, because the caller then should use lots of try/catch wrappers around file loading code, while instead a good-old boolean check would be just fine.
// *** I don't like this: ***
try
{
File f1 = loadFile("foo1");
}
catch(FileException& e)
{
...handle load failure, e.g. use some defaults for f1
}
doSomething();
try
{
File f2 = loadFile("foo2");
}
catch(FileException& e)
{
...handle load failure for f2
}
I prefer this style:
File f1 = loadFile("foo");
if (! f1.valid())
... handle load failure, e.g. use some default settings for f1...
doSomething();
File f2 = loadFile("foo2");
if (! f2.valid())
... handle load failure
Moreover, it may also make sense to make the File class movable (so you may also put File instances in containers, e.g. have a std::vector<File>), and in this case you must have an "invalid" state for a moved-from file instance.
So, for a File class, I'd consider the introduction of an invalid state to be just fine.
I also wrote a RAII template wrapper to raw resources, and I implemented an invalid state there as well. Again, this makes it possible to properly implement move semantics, too.
At least IMO, your thinking on this subject is probably better than that shown in iostreams. Personally, if I were creating an analog of iostreams from scratch today, it probably would not have a default ctor and separate open. When I use an fstream, I nearly always pass the file name to the ctor rather than default-constructing followed by using open.
Nearly the only point in favor of having a default ctor for a class like this is that it makes putting them into a collection easier. With move semantics and the ability to emplace objects, that becomes much less compelling though. It was never truly necessary, and is now almost irrelevant.
class C {
public
T x;
};
Is there an elegant way for the constructor of x to know implicitly in what instance of C it is constructing?
I've implemented such behavior with some dirty inelegant machinery. I need this for my sqlite3 wrapper. I don't like all wrappers I've seen, their API IMO ugly and inconvenient. I want something like this:
class TestRecordset: public Recordset {
public:
// The order of fields declarations specifies column index of the field.
// There is TestRecordset* pointer inside Field class,
// but it goes here indirectly so I don't have to
// re-type all the fields in the constructor initializer list.
Field<__int64> field1;
Field<wstring> field2;
Field<double> field3;
// have TestRecordset* pointer too so only name of parameter is specified
// in TestRecordset constructor
Param<wstring> param;
virtual string get_sql() {
return "SELECT 1, '1', NULL FROM test_table WHERE param=:PARAM";
}
// try & unlock are there because of my dirty tricks.
// I want to get rid of them.
TestRecordset(wstring param_value)
try : Recordset(open_database(L"test.db")), param("PARAM") {
param = param_value;
// I LOVE RAII but i cant use it here.
// Lock is set in Recordset constructor,
// not in TestRecordset constructor.
unlock(this);
fetch();
} catch(...) {
unlock(this);
throw;
}
};
I want to clarify the fact - it is a part of the working code. You can do this in C++. I just want to do it in a more nice way.
I've found a way to get rid of unlock and try block. I've remembered there is such a thing as thread local storage. Now I can write constructor as simple as that:
TestRecordset(wstring param_value):
Recordset(open_database(L"test.db")), param("PARAM") {
param = param_value;
fetch();
}
to dribeas:
My objective is to avoid redundant and tedious typing. Without some tricks behind the scene I will have to type for each Field and Param:
TestRecordset(wstring param_value): Recordset(open_database(L"test.db")), param(this, "PARAM"),
field1(this, 0), field2(this, 1), field3(this, 2) { ... }
It is redundant, ugly and inconvenient. For example, if I'll have to add new field in the
middle of SELECT I'll have to rewrite all the column numbers.
Some notes on your post:
Fields and Params are initialized by their default constructors.
Order of initializers in constructor is irrelevant. Fields are always initialized in order of their declaration. I've used this fact to track down column index for fields
Base classes are constructed first. So when Fields are constructed internal field list in Recordset are ready to use by Filed default constructor.
I CAN'T use RAII here. I need to acquire lock in Recorset constructor and release it obligatory in TestRecordset constructor after all Fields are constructed.
No. Objects aren't supposed to need to know where they're being used from in order to work. As far as x is concerned, it's an instance of T. That's it. It doesn't behave differently according to whether it's a member of class C, a member of class D, an automatic, a temporary, etc.
Furthermore, even if the T constructor did know about the instance of C, that instance of C would be incomplete since of course it has not finished construction yet, because its members haven't been constructed. C++ offers you plenty of chances to shoot yourself in the foot, but offering you a reference to an incomplete object in another class's constructor isn't one of them.
The only thing I can think of to approximate your code example is to do something like
#define INIT_FIELDS field1(this), field2(this), field3(this)
immediately after the list of fields, then use INIT_FIELDS in the initializer list and #undef it. It's still duplication, but at least it's all in one place. This will probably surprise your colleagues, however.
The other way to make sure you don't forget a field is to remove the zero-arg constructor from Field. Again, you still have to do the typing, but at least if you forget something the compiler will catch it. The non-DRY nature of initializer lists is, I think, something C++ just has to live with.
Adding on to One by One's answer, the actual question you should be asking is: "what is wrong with my solution design that it requires objects to know where they are instanciated?"
I don't think so.
Out of pure curiosity, why should it matter ? do you have a context in which this can be useful?
M.
I experiment with things like this in C# all the time - I use reflection to do it.
Consider getting a reflection or code generation library for C++ to help you do what you want to.
Now, I can't tell you how to find a good reflection or code generation library for C++, but that's a different question!
I am interested in your code. You comment that all fields plus the param attribute have pointers back into the TestRecordSet but that they don't need to be initialized? Or is it the object of the question, how to avoid having to pass the this pointers during construction?
If what you want is avoid adding all fields in the initialization list of your constructor, then it is a flawed objective. You should always initialize all your members in the initialization list and do so in the same order that they are declared in the class (this is not language enforced, but more of a globally learnt experience).
Your use of the try constructor block is just about he only recommended usage for that functionality (Anyone interested read GOTW#66) if it is indeed required. If the RecordSet member has been constructed (and thus the lock acquired) and something goes wrong afterwards in the constructor then [see quote below] the RecordSet will be destroyed and if it uses RAII internally it will free the lock, so I believe that the try/catch may not really be required.
C++03, 15.2 Exception Handling / Constructors and destructors
An object that is partially
constructed or partially destroyed
will have destructors executed for all
of its fully constructed subobjects,
that is, for subobjects for which the
constructor has completed execution
and the destructor has not yet begun
execution.
I'm adding some lazy initialization logic to a const method, which makes the method in fact not const. Is there a way for me to do this without having to remove the "const" from the public interface?
int MyClass::GetSomeInt() const
{
// lazy logic
if (m_bFirstTime)
{
m_bFirstTime = false;
Do something once
}
return some int...
}
EDIT: Does the "mutable" keyword play a role here?
Make m_bFirstTime mutable:
class MyClass
{
: :
mutable bool m_bFirstTime;
};
...but this is also very often an indication of a design flaw. So beware.
Actually, you said that you didn't want to change the header file. So your only option is to cast away the constness of the this pointer...
int MyClass::GetSomeInt() const
{
MyClass* that = const_cast<MyClass*>(this);
// lazy logic
if (that->m_bFirstTime)
{
that->m_bFirstTime = false;
Do something once
}
return some int...
}
If using mutable raises a red flag, this launches a red flag store in to orbit. Doing stuff like this is usually a really bad idea.
I think of this problem as involving two concepts: (1) "logically const" and (2) "bitwise const". By this I mean that getting some int from a class, does not logically change the class and in most cases it does not change the bits of the class members. However, in some cases, like yours, it does.
In these cases, where the method is logically const but not bitwise const, the compiler cannot know this. This is the reason for the existence of the mutable keyword. Use it as John Dibling shows, but it is not a design flaw. On the contrary, there are many cases where this is necessary. In your example, I presume that the calculation of the int is expensive, so we do not want to calculate it if it is not needed. In other cases, you may wish to cache results of methods for later use, etc.
BTW, even though you have accepted the "mutable" answer as correct, you do have to update the .h!
set the m_bFirstTime member to be mutable
As John Dibling said, mark the fields that are changed as mutable. The important part is in the comment by ypnos: 'don't really change the state of the object' (as perceived by the outside world). That is, any method call before and after the const method call must yield the same results. Else your design is flawed.
Some things that make sense to be mutable:
mutex or other lock types
cached results (that will not change)
Mutex are not part of your objects state, they are only a blocking mechanism to guarantee data integrity. A method that will retrieve a value from your class, does need to change the mutex, but your class data and state will be exactly the same after the execution of the const method as it was before.
With caching, you must consider that only data that it makes sense for data that is expensive to retrieve and assumed not to change (DNS result, as an example). Else you could be returning stale data to your user.
Some things that should not be changed inside const methods:
Anything that modifies the state of
the object
Anything that affects this or other
method results
Any user of your class that executes const methods will assume that your class (as seen from the outside world) will not change during the execution. It will be quite misleading and error prone if it were not the same. As an example, assume that a dump() method changes some internal variable -state, value- and that during debug the user of your class decides to dump() your object at a given point: your class will behave differently with traces than without: perfect debug nightmare.
Note that if you do lazy optimizations you must do them to access immutable data. That is, if your interface dictates that during construction you will retrieve an element from the database that can be later accessed through a constant method, then if you do lazy fetching of the data you can end up in a situation where the user constructs your object to keep a copy of the old data, modifies the database and later on decides to restore the previous data into the database. If you have performed a lazy fetch you will end up loosing the original value. An opposite example would be configuration file parsing if the config file is not allowed to be modified during the execution of the program. You can avoid parsing the file up the point where it is needed knowing that performing the read in the beginning or at a later time will yield the same result.
In any case - make note that this is no longer going to be thread safe. You can often rely on an object to be thread safe if it only has const methods (or you use only the const methods after initialization). But if those const methods are only logically const, then you lose that benefit (unless of course you start locking it all the time).
The only compiler optimization that could cause havok would be for the compiler to figure out that you're calling the method twice with the same arguments, and just reuse the first return value - which is fine as long as the function truly is logically const, and returns the same value for a given set of arguments (and object state). Even that optimization isn't valid if it's possible that anyone (including another thread) has had access to the object to call non-const methods on it.
mutable was added to the language specifically for this case. C++ is a pragmatic language, and is happy to allow corner cases like this to exist for when they are needed.