C++ : call to temporary is a no-op
-
This is by concept of Qt I think. I am wondering why they have decided to return a copy and not a reference to the original field.
On a number of topics, C++ tutorials say it is mostly better to return references instead of copies to reduce the number of copy tasks. Quite all methods with QStrings as parameter are asking for references not copies.
Is there a reasonable explanation why this here is different?
"Love it or change it" - I don't can/want to change it. But I want to understand why this solution was choosen.
-
@aha_1980 said in C++ : call to temporary is a no-op:
@MasterQ said in C++ : call to temporary is a no-op:
I don't want to alter the field object but only to call its setValue method.
Then you have a conceptual problem.
really? For me it is a difference between altering an object instance and altering the content of an object (instance).
A setter is modifying the content of an instance of an object, not the instance itself.
But that is another topic.
@MasterQ said in C++ : call to temporary is a no-op:
For me it is a difference between altering an object instance and altering the content of an object (instance).
Think about what defines an "object"...
Say you have an object:
Blubb blubb
and a pointer to it:
Blubb *pBlubb = &blubb
In memory:
0x000000 - 0x000004| x | x | x | x | x |
Blubb *pBlubb
could look like this:ptr = 0x000000 (sizeOfBlubb) | | | x | x | x | x | x |
So if you modify the content of your
Blubb
in memory, either via pointer access or change the object itself:| x | x | y | y | y |
the "content" = "instance" changes (what bytes are written to the memory).
What does not change, is the pointer
pBlubb
to yourBlubb
object.... it still points whereBlubb
starts in memory...This is just a simplification, there's much more going on...
I don't understand what you want to tell us with the sentence above ;-)
(Off-topic)
Edit:
Knowing this also helps to understand the difference between:[ 0 ] Blubb *pBlubb; [ 1 ] const Blubb *pBlubb; [ 2 ] Blubb *pBlubb const; [ 3 ] Blubb *const pBlubb; [ 4 ] const Blubb *pBlubb const;
Ask yourself, what can be changed from [0] - [4].
@MasterQ said in C++ : call to temporary is a no-op:
This is by concept of Qt I think. I am wondering why they have decided to return a copy and not a reference to the original field.
Because
QSqlField
is not aQObject
...
It's a registeredQMetaObject
kind of "struct"....
and, as the documentation states, implicitly-shared... so even "copies" share the same memory until you detach them manually or by modifying one of them. -
Hello,
I have a class derived from QSqlRecord. Trying to write a setter for a field I get the mentioned message.
But why is
field
here temporary?class D:QSqlRecord{ public: void setId(int id){ field(0).setValue(id);} }
I have to write
void setId(int id){ auto f = field(0); f.setValue(id); replace(0, f); }
Is it really necessary to create a copy, modify it and to replace the original one with it? I don't want to alter the field object but only to call its setValue method.
@MasterQ said in C++ : call to temporary is a no-op:
void setId(int id){ field(0).setValue(id);}
Are you aware that (to change the value in a
QSqlRecord
) you are intended to write:setValue(0, id); // or setValue("id", id);
-
I am not a professional and maybe my wording is not correct by 100%.
I know what you want to say.
Back to the topic.
@Pl45m4 said in C++ : call to temporary is a no-op:
Because
QSqlField
is not aQObject
...
It's a registeredQMetaObject
kind of "struct"....
and, as the documentation states, implicitly-shared... so even "copies" share the same memory until you detach them manually or by modifying one of them.from my documentation:
The QSqlField **class** manipulates the fields in SQL database tables and views.
andA QSqlField **object** can provide some meta-data about the field, ...
meta-data
? sounds like QObject. But maybe not by 100%? If I remember right, all Qt stuff is derived from QObject.and from source code
class Q_SQL_EXPORT QSqlField { ...
I am a little more confused now.
Nevertheless, it is as it is. I now know about and that's fine.
BTW: Is there a tool to show the full hierarchical tree of Qt-Classes?
Sorry if I am bothering you but I am always trying to dig to the ground of things I don't understand.
-
@MasterQ said in C++ : call to temporary is a no-op:
void setId(int id){ field(0).setValue(id);}
Are you aware that (to change the value in a
QSqlRecord
) you are intended to write:setValue(0, id); // or setValue("id", id);
@JonB said in C++ : call to temporary is a no-op:
Are you aware that (to change the value in a
QSqlRecord
) you are intended to write:
...Yes!
full citation:
class AccountTransactionsTagEntity : public QSqlRecord { //Q_OBJECT public: AccountTransactionsTagEntity(); AccountTransactionsTagEntity(AccountTransactionsTagEntity const &entity); AccountTransactionsTagEntity(AccountTransactionsTagEntity const &&entity) noexcept; explicit AccountTransactionsTagEntity(QSqlRecord const &record); explicit AccountTransactionsTagEntity(QSqlRecord const &&record); [[nodiscard]] int id() const { return field(Id).value().toInt(); } [[nodiscard]] int categorieId() const { return field(CategoryId).value().toInt(); } [[nodiscard]] QString pattern() const { return field(Pattern).value().toString(); } [[nodiscard]] QString description() const { return field(Description).value().toString(); } void setId(int id) { auto f = field(Id); f.setValue(id); replace(Id, f); } // // void setCategorieId(int id) { field(CategoryId).setValue(id); } // void setPattern(QString pattern) { field(Pattern).setValue(pattern); } // void setDescription() { field(Description).value().toString(); } enum Datafield { Id = 0, CategoryId, Pattern, Description }; };
-
@JonB said in C++ : call to temporary is a no-op:
Are you aware that (to change the value in a
QSqlRecord
) you are intended to write:
...Yes!
full citation:
class AccountTransactionsTagEntity : public QSqlRecord { //Q_OBJECT public: AccountTransactionsTagEntity(); AccountTransactionsTagEntity(AccountTransactionsTagEntity const &entity); AccountTransactionsTagEntity(AccountTransactionsTagEntity const &&entity) noexcept; explicit AccountTransactionsTagEntity(QSqlRecord const &record); explicit AccountTransactionsTagEntity(QSqlRecord const &&record); [[nodiscard]] int id() const { return field(Id).value().toInt(); } [[nodiscard]] int categorieId() const { return field(CategoryId).value().toInt(); } [[nodiscard]] QString pattern() const { return field(Pattern).value().toString(); } [[nodiscard]] QString description() const { return field(Description).value().toString(); } void setId(int id) { auto f = field(Id); f.setValue(id); replace(Id, f); } // // void setCategorieId(int id) { field(CategoryId).setValue(id); } // void setPattern(QString pattern) { field(Pattern).setValue(pattern); } // void setDescription() { field(Description).value().toString(); } enum Datafield { Id = 0, CategoryId, Pattern, Description }; };
@MasterQ
So that is what you should do! There are no "temporaries" or "copying of ..." if you do it that way.If I remember right, all Qt stuff is derived from QObject.
Not at all. And
QSqlField
is not aQObject
. Nor areQString
,QList
, .... The docs would always tell you what a class inherits,QObject
or otherwise, right at the start of the page. -
I am not a professional and maybe my wording is not correct by 100%.
I know what you want to say.
Back to the topic.
@Pl45m4 said in C++ : call to temporary is a no-op:
Because
QSqlField
is not aQObject
...
It's a registeredQMetaObject
kind of "struct"....
and, as the documentation states, implicitly-shared... so even "copies" share the same memory until you detach them manually or by modifying one of them.from my documentation:
The QSqlField **class** manipulates the fields in SQL database tables and views.
andA QSqlField **object** can provide some meta-data about the field, ...
meta-data
? sounds like QObject. But maybe not by 100%? If I remember right, all Qt stuff is derived from QObject.and from source code
class Q_SQL_EXPORT QSqlField { ...
I am a little more confused now.
Nevertheless, it is as it is. I now know about and that's fine.
BTW: Is there a tool to show the full hierarchical tree of Qt-Classes?
Sorry if I am bothering you but I am always trying to dig to the ground of things I don't understand.
@MasterQ said in C++ : call to temporary is a no-op:
from my documentation:
The QSqlField class manipulates the fields in SQL database tables and views.
andA QSqlField object can provide some meta-data about the field, ...
meta-data? sounds like QObject. But maybe not by 100%? If I remember right, all Qt stuff is derived from QObject.
So you must have a different documentation on Qt :)
If
QSqlField
would be aQObject
, its inheritance hierarchy would be listed below theqmake
row in that table at the start of the page.@MasterQ said in C++ : call to temporary is a no-op:
BTW: Is there a tool to show the full hierarchical tree of Qt-Classes?
There's a listing of all classes and all modules, but unfortunately without any tree-like relation between them.
As @JonB said and I mentioned above, you can check the "header" in the official documentation pages of anyQ....
class of interest and you will see the direct inherited and inheriting classes... you can follow that route by clicking them :) -
@MasterQ said in C++ : call to temporary is a no-op:
from my documentation:
The QSqlField class manipulates the fields in SQL database tables and views.
andA QSqlField object can provide some meta-data about the field, ...
meta-data? sounds like QObject. But maybe not by 100%? If I remember right, all Qt stuff is derived from QObject.
So you must have a different documentation on Qt :)
If
QSqlField
would be aQObject
, its inheritance hierarchy would be listed below theqmake
row in that table at the start of the page.@MasterQ said in C++ : call to temporary is a no-op:
BTW: Is there a tool to show the full hierarchical tree of Qt-Classes?
There's a listing of all classes and all modules, but unfortunately without any tree-like relation between them.
As @JonB said and I mentioned above, you can check the "header" in the official documentation pages of anyQ....
class of interest and you will see the direct inherited and inheriting classes... you can follow that route by clicking them :)@Pl45m4 said in C++ : call to temporary is a no-op:
So you must have a different documentation on Qt :)
Noooo! ;-)
If
QSqlField
would be aQObject
, its inheritance hierarchy would be listed below theqmake
row in that table at the start of the page.I got it! That explains some other issues I had.
@MasterQ said in C++ : call to temporary is a no-op:
BTW: Is there a tool to show the full hierarchical tree of Qt-Classes?
... you can follow that route by clicking them :)
I expected that ... unfortunately! :-(
Thanks.
-
Object and QObject are two different things. An object is an instance of a class (c++ basics) , a QObject is a Qt (base) class.
-
@JonB said in C++ : call to temporary is a no-op:
Are you aware that (to change the value in a
QSqlRecord
) you are intended to write:
...Yes!
full citation:
class AccountTransactionsTagEntity : public QSqlRecord { //Q_OBJECT public: AccountTransactionsTagEntity(); AccountTransactionsTagEntity(AccountTransactionsTagEntity const &entity); AccountTransactionsTagEntity(AccountTransactionsTagEntity const &&entity) noexcept; explicit AccountTransactionsTagEntity(QSqlRecord const &record); explicit AccountTransactionsTagEntity(QSqlRecord const &&record); [[nodiscard]] int id() const { return field(Id).value().toInt(); } [[nodiscard]] int categorieId() const { return field(CategoryId).value().toInt(); } [[nodiscard]] QString pattern() const { return field(Pattern).value().toString(); } [[nodiscard]] QString description() const { return field(Description).value().toString(); } void setId(int id) { auto f = field(Id); f.setValue(id); replace(Id, f); } // // void setCategorieId(int id) { field(CategoryId).setValue(id); } // void setPattern(QString pattern) { field(Pattern).setValue(pattern); } // void setDescription() { field(Description).value().toString(); } enum Datafield { Id = 0, CategoryId, Pattern, Description }; };
@MasterQ said in C++ : call to temporary is a no-op:
full citation:
You wrote/added this after I wrote about using
QSqlRecord::setValue()
. I am unclear: are you aware that what you show in your "full citation" is not the (best) way to read or write a value in aQSqlRecord
(and you should change)? Just checking.While on the topic you mentioned "isn't everything in Qt a
QObject
" and you are investigating Qt, have you read Implicit Sharing? The list on that page includesQSqlField
(andQSqlRecord
). It is worth understanding this concept in Qt code too. NoQObject
s are implicitly shared. -
Object and QObject are two different things. An object is an instance of a class (c++ basics) , a QObject is a Qt (base) class.
@Christian-Ehrlicher said in C++ : call to temporary is a no-op:
Object and QObject are two different things. An object is an instance of a class (c++ basics) , a QObject is a Qt (base) class.
I never claimed
object
andQObject
are the same thing. I mentioned the doc since @Pl45m4 said QSqlField would be a struct.@JonB said in C++ : call to temporary is a no-op:
@MasterQ said in C++ : call to temporary is a no-op:
full citation:
You wrote/added this after I wrote about using
QSqlRecord::setValue()
. I am unclear: are you aware that what you show in your "full citation" is not the (best) way to read or write a value in aQSqlRecord
(and you should change)? Just checking.I am not sure if I got you. You mean the version to address the field by name is better as to address by index, right? Since I have full controll about the structure of the database I also have full control of the sequence of the fields. I agree that by name is a safer way to do it. Maybe I will change in future. At the moment there are other issues with higher priority.
While on the topic you mentioned "isn't everything in Qt a
QObject
" and you are investigating Qt, have you read Implicit Sharing?No, I was not aware of that topic. Thanks for pointing to.
-
@MasterQ said in C++ : call to temporary is a no-op:
For me it is a difference between altering an object instance and altering the content of an object (instance).
Think about what defines an "object"...
Say you have an object:
Blubb blubb
and a pointer to it:
Blubb *pBlubb = &blubb
In memory:
0x000000 - 0x000004| x | x | x | x | x |
Blubb *pBlubb
could look like this:ptr = 0x000000 (sizeOfBlubb) | | | x | x | x | x | x |
So if you modify the content of your
Blubb
in memory, either via pointer access or change the object itself:| x | x | y | y | y |
the "content" = "instance" changes (what bytes are written to the memory).
What does not change, is the pointer
pBlubb
to yourBlubb
object.... it still points whereBlubb
starts in memory...This is just a simplification, there's much more going on...
I don't understand what you want to tell us with the sentence above ;-)
(Off-topic)
Edit:
Knowing this also helps to understand the difference between:[ 0 ] Blubb *pBlubb; [ 1 ] const Blubb *pBlubb; [ 2 ] Blubb *pBlubb const; [ 3 ] Blubb *const pBlubb; [ 4 ] const Blubb *pBlubb const;
Ask yourself, what can be changed from [0] - [4].
@MasterQ said in C++ : call to temporary is a no-op:
This is by concept of Qt I think. I am wondering why they have decided to return a copy and not a reference to the original field.
Because
QSqlField
is not aQObject
...
It's a registeredQMetaObject
kind of "struct"....
and, as the documentation states, implicitly-shared... so even "copies" share the same memory until you detach them manually or by modifying one of them.@MasterQ said in C++ : call to temporary is a no-op:
No, I was not aware of that topic. Thanks for pointing to.
I explained here already:
@Pl45m4 said in C++ : call to temporary is a no-op:
@MasterQ said in C++ : call to temporary is a no-op:
This is by concept of Qt I think. I am wondering why they have decided to return a copy and not a reference to the original field.
Because QSqlField is not a QObject...
It's a registered QMetaObject kind of "struct"....
and, as the documentation states, implicitly-shared... so even "copies" share the same memory until you detach them manually or by modifying one of them.To sum this up:
QSqlField
is just a data struct, but registered in the meta object system (still not aQObject
).
It contains the column data of a database table (or of the current view on it).
It is implicitly-shared, which means, for 5000 copies of the same record it does not copy the data 5000 times...
Even though they are copies, they share the same data in memory, which means, they are the same until you change something...
Then the modified field detaches and all data is copied, separating the modified field from the others and making it unique.
In memory (your "objects"), you would have 4999 objects which share one memory and for the detached object the data is copied to a new address.And as @aha_1980 said in C++ : call to temporary is a no-op:
Then back to topic: field(0) returns a copy, so calling field(0).setValue(id) modifies the temporary copy.
If I'm not wrong,
setValue(id)
will obviously modify/change the field... which causes the detachment... making a new, temporary field :) -
@Christian-Ehrlicher said in C++ : call to temporary is a no-op:
Object and QObject are two different things. An object is an instance of a class (c++ basics) , a QObject is a Qt (base) class.
I never claimed
object
andQObject
are the same thing. I mentioned the doc since @Pl45m4 said QSqlField would be a struct.@JonB said in C++ : call to temporary is a no-op:
@MasterQ said in C++ : call to temporary is a no-op:
full citation:
You wrote/added this after I wrote about using
QSqlRecord::setValue()
. I am unclear: are you aware that what you show in your "full citation" is not the (best) way to read or write a value in aQSqlRecord
(and you should change)? Just checking.I am not sure if I got you. You mean the version to address the field by name is better as to address by index, right? Since I have full controll about the structure of the database I also have full control of the sequence of the fields. I agree that by name is a safer way to do it. Maybe I will change in future. At the moment there are other issues with higher priority.
While on the topic you mentioned "isn't everything in Qt a
QObject
" and you are investigating Qt, have you read Implicit Sharing?No, I was not aware of that topic. Thanks for pointing to.
@Pl45m4 said in C++ : call to temporary is a no-op:
@MasterQ said in C++ : call to temporary is a no-op:
No, I was not aware of that topic. Thanks for pointing to.
I explained here already:
Because QSqlField is not a QObject...
It's a registered QMetaObject kind of "struct"....
and, as the documentation states, implicitly-shared... so even "copies" share the same memory until you detach them manually or by modifying one of them.This was misleading, sorry. I thought you were talking about the
QSqlField
documentation. But you meant the implicit shared documentation?In the documenation to
QSqlField
implicit sharing is not mentioned.If I'm not wrong,
setValue(id)
will obviously modify/change the field...Yes, you are right! ;-)
-
implicit sharing ... read ... understood ... check!
I now also know, what this suspicious d pointer is.
@MasterQ said in C++ : call to temporary is a no-op:
I now also know, what this suspicious d pointer is.
Haha we shouldn't start to discuss Qt implementation details and strategies here, as the topic is quite a mess already and confusing for future readers :)
The d- and q-pointers have nothing to do with anything here and are a whole new story :)
They are a product of how Qt's internal classes are organized and belong to the pIMPL idiom.@MasterQ said in C++ : call to temporary is a no-op:
In the documenation to QSqlField implicit sharing is not mentioned.
But it is mentioned that
QSqlRecord
andQSqlField
are implicitly shared
Btw: many classes contain that hint... if you know, you know.
And if you read it once, in the future you know right away what you are dealing with :)QSqlField is part of Database Classes and Implicitly Shared Classes.
( https://doc.qt.io/qt-6/qsqlfield.html ) -
@Christian-Ehrlicher said in C++ : call to temporary is a no-op:
Object and QObject are two different things. An object is an instance of a class (c++ basics) , a QObject is a Qt (base) class.
I never claimed
object
andQObject
are the same thing. I mentioned the doc since @Pl45m4 said QSqlField would be a struct.@JonB said in C++ : call to temporary is a no-op:
@MasterQ said in C++ : call to temporary is a no-op:
full citation:
You wrote/added this after I wrote about using
QSqlRecord::setValue()
. I am unclear: are you aware that what you show in your "full citation" is not the (best) way to read or write a value in aQSqlRecord
(and you should change)? Just checking.I am not sure if I got you. You mean the version to address the field by name is better as to address by index, right? Since I have full controll about the structure of the database I also have full control of the sequence of the fields. I agree that by name is a safer way to do it. Maybe I will change in future. At the moment there are other issues with higher priority.
While on the topic you mentioned "isn't everything in Qt a
QObject
" and you are investigating Qt, have you read Implicit Sharing?No, I was not aware of that topic. Thanks for pointing to.
@MasterQ said in C++ : call to temporary is a no-op:
I never claimed object and QObject are the same thing
A QSqlField object can provide some meta-data about the field, ...
meta-data? sounds like QObject.
But you wrote it...
-
M MasterQ has marked this topic as solved on
-
@Christian-Ehrlicher said in C++ : call to temporary is a no-op:
Object and QObject are two different things. An object is an instance of a class (c++ basics) , a QObject is a Qt (base) class.
I never claimed
object
andQObject
are the same thing. I mentioned the doc since @Pl45m4 said QSqlField would be a struct.@JonB said in C++ : call to temporary is a no-op:
@MasterQ said in C++ : call to temporary is a no-op:
full citation:
You wrote/added this after I wrote about using
QSqlRecord::setValue()
. I am unclear: are you aware that what you show in your "full citation" is not the (best) way to read or write a value in aQSqlRecord
(and you should change)? Just checking.I am not sure if I got you. You mean the version to address the field by name is better as to address by index, right? Since I have full controll about the structure of the database I also have full control of the sequence of the fields. I agree that by name is a safer way to do it. Maybe I will change in future. At the moment there are other issues with higher priority.
While on the topic you mentioned "isn't everything in Qt a
QObject
" and you are investigating Qt, have you read Implicit Sharing?No, I was not aware of that topic. Thanks for pointing to.
@MasterQ said in C++ : call to temporary is a no-op:
I am not sure if I got you. You mean the version to address the field by name is better as to address by index, right?
No. I am saying your way of coding, going via a
QSqlField
and commenting on the copying/temporaries etc. is "wrong", at least efficiency-/lines-of-code-wise, for both writing and reading your fields. (Nothing to do with integer indexing vs name indexing, they are just alternatives, integer indexing is faster.) You do not and should not need to accessfield()
at all in either. You simply need:int id() const { return value(Id).toInt(); } void setId(int id) { setValue(Id, id); }
and so on for all your field getters/setters. None of that 3-lines-to-set! Do not go via QSqlRecord::field() at all, forget about
QSqlField
, just use QSqlRecord::value()/setValue().