The following is an example of my typical code. A have a lot of objects that look like this:
struct Config
{
Config();
Config(const std::string& cType, const std::string& nType); //additional variables omitted
Config(Config&&) = default;
Config& operator=(Config&&) = default;
bool operator==(const Config& c) const;
bool operator!=(const Config& c) const;
void doSomething(const std::string& str);
bool doAnotherThing(const MyOtherObject& obj);
void doYetAnotherThing(int value1, unsigned long value2, const std::string& value3, MyEnums::Seasons value4, const std::vector<MySecondObject>& value5);
std::string m_controllerType;
std::string m_networkType;
//...
};
//...
Config::Config(const std::string& cType, const std::string& nType) :
m_controllerType(cType),
m_networkType(nType)
{
}
My motivations and general understand of the subject:
- use const references in constructors and methods to avoid double-copying when passing objects.
- simple types - pass by value; classes and structs - pass by const reference (or simple reference when I need to modify them)
- force compiler to create
default
move constructor and move assignment so that It would be able to do it's fancy magic and simultaneously it allows to avoid writing boringctor() : m_v1(std::move(v1)), m_v2(std::move(v2)), m_v3(std::move(v3)) {}
. - if it performs badly, use libc and raw pointers, then wrap it at class and write a comment.
I have a strong feeling that by rules of thumb are flawed and simply incorrect.
After reading cppreference, Scott Mayers, C++ standard, Stroustrup and so on, I feel like: "Yea, I understand every word here, but it still doesn't make any sense'. The only thing I king of understood is that move semantics makes sense when my class contains non-copiable types, like std::mutex
and std::unique_ptr
.
I've seen a lot of code where people pass complex object by value, like large strings, vectors and custom classes - I believe this is where move semantics happen, but, again, how can you pass an object to a function by move? If I am correct, it would leave an object in a "kind-of-null-state", making it unusable.
So, the questionы are: - How do I correctly decide between pass-by-value and pass-by-reference? - Do I need to provide both copy and move constructors? - Do I need to explicitly write move and copy constructors? May I use = default
? My classes are mostly POD object so there is no complex login involved. - When debugging, I can always write std::cout << "move\n";
or std::cout << "copy\n";
in constructors of my own classes, but how do I know what happens with classes from stdlib
?
P.S. It may look like it is a cry out of desperation (it is), not a valid SO question. I simply don't know to formulate my problems better than this.
Aucun commentaire:
Enregistrer un commentaire