Is std::move overkill in this situation? - c++

I was wondering if using the std::move() in this example is overkill or computationally more expensive than simply copying it? I would really like to know.
class Student
{
private:
std::string _studentName;
int _studentGrade;
public:
Student() : _studentName("No Name"), _studentGrade(0) {}
std::string Name() const { return _studentName; }
void Name(std::string x) { _studentName = std::move(x); }
int Grade() const { return _studentGrade; }
void Grade(int x) { _studentGrade = std::move(x); }
};

Reading the core guidelines at F.call: Parameter passing, we can deduce a few recommendations.
Use move only when you want to optimize for rvalue. If you find that it does an improvement on performance, it's up to you to do it.
You could receive by value then move as it optimises rvalues calls into your setters, but it pessimizes lvalues. This is because std::string will reuse its storage and not cause unnecessary allocations when copying from the const reference. Copying into the value parameter always end up allocating when no SSO is possible.
The preferred way, especially for setters are to use const reference, and add an rvalue reference overload when rvalues are passed into the setter:
class Student
{
private:
std::string _studentName;
int _studentGrade;
public:
Student() : _studentName("No Name"), _studentGrade(0) {}
std::string_view Name() const { return _studentName; }
void Name(std::string const& x) { _studentName = x; }
// add this when you need to optimize for rvalues.
// optimizing for rvalues is not always needed.
// They can speedup quite a bit when actually needed.
void Name(std::string&& x) { _studentName = std::move(x); }
// int is a trivial type, so move does nothing. No move needed.
int Grade() const { return _studentGrade; }
void Grade(int x) { _studentGrade = x; }
}
For the int, std::move won't do anything, it's still a copy. Just take them by value and return them by value.
However, the best you can do is much simpler:
class Student
{
public:
std::string studentName;
int studentGrade;
};
Since your setters don't enforce any invariants, you'd be better off using public members. You don't need overloads and reference since std::string implements it for you.

Related

How to avoid polymorphism?

I have a data type OperationSequence. Below is OperationSequence.h
class OperationSequence
{
public:
void appendOperation(std::function<double(double)> operation);
void moveOperation(int operation_index);
void eraseOperation(int operation_index);
const std::vector<std::function<double(double)>>& data() const;
private:
std::vector<std::function<double(double)>> operation_sequence;
};
double executeSequence(const OperationSequence& operation_sequence, double value);
void executeSequence(const OperationSequence& operation_sequence, const std::string& file_name);
I have to implement printOperationSequence(const OperationSequence& operation_sequence).
Assignment set a requirement on operation to be f: double -> double. Some operations like Addition and Multiplication were also requested.
Obvious implementation would be to create an Interface Operation and have it be callable with f: double -> double and have a std::string getName() method.
What would be a good way for OperationSequence to remain this generic but also making it easy and efficient to print out OperationSequence in a meaningful way?
Meaningful way being something like Multiplication, Addition, ...
Is delegating construction to some other class that will also create a operation_name_sequence a good idea?
P.S. Feel free to improve the question title :D
If you want to avoid to have polymorphism (even if std::function uses it or similar for type erasure), you might create class Operation to add name to the function:
struct Operation
{
std::string name;
std::function<double(double)> f;
};
class OperationSequence
{
public:
void appendOperation(const Operation& operation);
void appendOperation(const std::string& name, std::function<double(double)> f);
void moveOperation(int operation_index);
void eraseOperation(int operation_index);
const std::vector<Operation>& data() const;
private:
std::vector<Operation> operations;
};
then
void printOperationSequence(const OperationSequence& operation_sequence)
{
for (const auto& op : operation_sequence.data()) {
std::cout << op.name << std::endl;
}
}

How to use immutable object without operator=() in procedural code

Given an immutable C++ object (its members are const, which means its operator=() method does not exist), how do you implement this simple procedural pattern (which would require Object::operator=() to exist):
Object someObject {17};
// ...
if (...) {
someObject = Object {42};
}
// ...
use(someObject);
A workaround is to use shared_ptr.
shared_ptr<Object> someObject(new Object(17));
shared_ptr<Object> anotherObject(new Object(42));
// ...
if (...) {
someObject = anotherObject;
}
use(someObject);
My pattern in such a situation is to extract initialization code into a function:
Object ini(...){
if(...) {
return Object{42};
}
return Object{17};
}
.....
Object someObject=ini(...);// copy constructor used (or not, because of RVO)
use(someObject);
If initialization is simple you could use:
Object someObject = ...? Object{42} : Object{17};
It is not very different to declaring your o-variable const.
If the someObject=17 is used and then replaced with someObject=42 - it's just undermining the good intentions which were pursued by declaring some members const.
There are two alternatives:
declaring some members const was not such bright idea - it can be undone and an assigment operator can be added.
using Object as it was meant to be used.
What should not be done lightly: making some tricks with pointers/references - it will just make your code more complex as it is. Better to use a new variable if needed:
Object someObject {17};
// ...
Object newSomeObject = ... ? Object {42} : someObject {17};
use(newSomeObject);
In the case that copying of the old object could be a performance problem, the code can be refactored in such a way, that
use(need42(..) ? create42() : object17);
can be used without copying data. This solution assumes that use uses a const reference of its argument or the parameter is passed by-value.
In my opinion every change of an immutable object should yield a new object, otherwise, the following can happen:
ImmutableObject obj(1);
ImmutableObject &ref=obj;//ref.member=1
...
obj=ImmutableObject(2);
//ref.member!=1, that is puzzling, I assumed ref to be immutable!
Now, the user of your object (via ref) gets irritated because the object was changed! The whole point of the immutability is that you can reason, that the values never ever change. If they can change, there is not that many advantages in using "immutables" in the first place.
The other answers work when your initialization logic may be simple, but if you're detangling some spaghetti code, this might help.
If it isn't, take from java (they might not have invented it, but I see java programmers use this most) -- the builder pattern. Here are two possible ways of implementing it in C++.
#include <string>
class ImmutableClass {
public:
ImmutableClass(int a, int b, std::string c) : a_(a), b_(b), c_(c) {}
// Getters...
private:
ImmutableClass& operator=(const ImmutableClass&) = delete;
const int& GetA() {return a_;}
const int& GetB() {return b_;}
const std::string& GetC() {return c_;}
const int a_;
const int b_;
const std::string c_;
};
struct ImmutableClassBuilderExampleOne {
public:
// Note the default initialization to avoid undefined behavior.
int a = 0;
int b = 0;
std::string c;
};
// Less boilerplate, less encapsulation, if that's your thing.
ImmutableClass BuildImmutableClass(const ImmutableClassBuilderExampleOne& icb) {
return ImmutableClass(icb.a, icb.b, icb.c);
}
// More boilerplate, more encapsulation, can be "tidied" with macros.
class ImmutableClassBuilderExampleTwo {
public:
const ImmutableClass build() {
return ImmutableClass(a_, b_, c_);
}
ImmutableClassBuilderExampleTwo& setA(const int a) {
a_ = a;
return *this;
}
ImmutableClassBuilderExampleTwo& setB(const int b) {
b_ = b;
return *this;
}
ImmutableClassBuilderExampleTwo& setC(const std::string& c) {
c_ = c;
return *this;
}
private:
// Note the default initialization to avoid undefined behavior.
int a_ = 0;
int b_ = 0;
std::string c_;
};

Is overloading operator() for a reconstruction a good practice?

I was thinking of the following scenario:
class A {
private:
std::string id;
std::array<std::string, 128> data;
public:
A(const std::string& id) : id(id) {}
A(const A& other) : id(other.id), data(other.data) {}
virtual ~A(){}
//to override the intern data
A& operator=(const A& other) {
this->data = other.data;
return *this;
}
//to override the whole element
A& operator()(const A& other) {
this->id = other.id;
this->data = other.data;
return *this;
}
};
As you can see, my idea was to use operator= to override the internal data and operator() to override the whole element. I was inspired by the constructor which would allow A a(anOtherA); to construct the element and I would like to override this for a re-construction. Now I don't now if this would be smart overloading this because it's actually the function call operator.
Is overloading operator() for a reconstruction a good practice?
In short no, that isn't good practice. Such just obfuscates what is done under the hood.
Providing a setter for data and use the code you provided in your overloaded operator() for the implementation of the assignment operator=() would provide the clearer and naturally expected semantics:
class A {
private:
std::string id;
std::array<std::string, 128> data;
public:
A(const std::string& id) : id(id) {}
A(const A& other) : id(other.id), data(other.data) {}
~A(){}
//to override the intern data
A& operator=(const A& other) {
id = other.id;
data = other.data;
return *this;
}
//to override the intern data
void setData(const A& other) {
data = other.data;
}
void setData(const std::array<std::string, 128>& data_) {
data = data_;
}
};
The semantics of the operator() isn't that clearly defined (vs the operator=()) beyond you can make a call of your class looking like a "normal" function call (which is mostly useful with templates taking your type as a parameter).
But I'd expect it more to do some action instead of changing the internal state of the class.
Regarding the style, instead of the set / get prefixes for getter/setter functions I prefer what's done in the c++ standard library, (like e.g. with the std::ios_base::flags() property):
class A {
private:
// ...
std::array<std::string, 128> data_;
public:
const std::array<std::string, 128>& data() const {
return data_;
}
void data(const std::array<std::string, 128>& data) {
data_ = data;
}
// ...
};
great answer from πάντα ῥεῖ so please upvote that answer, not this one.
As you write, and more importantly, read more c++ you will come to appreciate people who name methods and functions with natural, meaningful names.
For most of us, if we see code like this:
X x;
Y y;
x(y);
We would think, before even looking at the declarations of X and Y, that X is some kind of function object (i.e. it does something) and Y is some kind of data or state object - it likes having things done to it, or it supplies data or services.
As a side note, a Haskell programmer would naturally assume that Y is also a function, but that's another story.
If your implementation of X::operator()(Y) does not "do X-type stuff with or to a Y" then it is probably inappropriately named.
If Y actually represents new state for X, and X intends to 'reset' itself using the data in Y, then the method should probably be called... reset:
X x;
Y y;
x.reset(y); //ok, this is telling a better story
With reasonable names we can tell a narrative with our code:
void processResults(XFactory& factory, std::istream& is) {
while(is) {
auto x = X::createFrom(factory);
x.collectNResults(is, 10);
auto a = x.takeAverage();
storeAverage(a);
x.reset(y);
}
}
Now even without looking up the definitions of the various classes I can get a sense of the general narrative. It's easier on the eye and I'm going to be able to hone in on the bits I need to see much more quickly than:
void processResults(XFactory& factory, std::istream& is) {
while(is) {
auto x = X(factory);
x(is, 10);
auto a = x();
x(averageStore);
x(y);
}
}
Which is what I'd have if I wrote every operation on an X in terms of a call operator which, much like corporate tax avoidance, is actually perfectly legal, but nevertheless happens to upset other people because they end up paying the price for your selfishness.

Over-using mutable to enhance security?

Suppose I have a class that has an array of pointers, and I have a method that dereferences a pointer and returns it as a reference. I want to allow the method caller to call non-const methods of the object the pointer is pointing to, but also want to protect myself from the caller changing what the pointer is pointing to. If I return a const reference, I have to mark many of the pointer object's methods as const, and hence many of its class member variables as mutable.
Is this bad practice? If so, how do I get around this?
Is there performance penalty for over-using mutable?
Example:
#include <iostream>
#include <array>
#include <memory>
class Counter
{
public:
Counter();
void hit() const;
void reset();
unsigned count() const;
private:
mutable unsigned count_;
};
Counter::Counter() : count_(0) {}
void Counter::hit() const { ++count_; }
void Counter::reset() { count_ = 0; }
unsigned Counter::count() const { return count_; }
class CircularArray
{
public:
CircularArray();
const Counter& next() const;
private:
mutable unsigned i_;
std::array<std::unique_ptr<Counter>, 3> arr_;
};
CircularArray::CircularArray() : i_(2)
{
arr_[0] = std::unique_ptr<Counter>(new Counter);
arr_[1] = std::unique_ptr<Counter>(new Counter);
arr_[2] = std::unique_ptr<Counter>(new Counter);
}
const Counter& CircularArray::next() const { return *arr_[(i_ = (i_ + 1) % 3)]; }
int main()
{
CircularArray circular;
const Counter* p;
p = &circular.next();
p->hit();
p->hit();
Counter c;
//*p = c; // <-- Want to prevent this
}
To extend what I was saying, there is no point in abusing mutable for this. If this is all you want to prevent:
*p = /* ... */;
then it can be done much more easily by deleting the assignment operator of Counter:
class Counter
{
void operator=(const Counter&) = delete;
// ...
};
Remember that the assignment operator does not affect the identity of the object: it doesn't change its address. Semantically, an assignment involving of modifying this object to replicate the state of another object. In fact, even if you forbid me from using the assignment operator somehow, I could still do this:
// a very inefficient way of performing `*p = c`
p->reset();
while (p->count() != c.count())
p->hit();
This achieves the exact same result as performing an assignment, albeit very clumsily and inefficiently.
Performing an assignment is no different than calling a non-const member function that accepts a single argument of type const Counter&. Hypothetically, you could redefine the assignment operator to do absolutely nothing at all if you wanted to (it would be a bad idea though).

Custom swap boilerplate

As I understand copy-and-swap idiom, it has a drawback of needing of bolierplate code. Consider a simple "just-hold-all-those-damn-lemons" struct:
struct MuchData {
private:
std::string one, two;
int three;
std::vector<Something> four;
MyType five;
MyOtherType six, seven;
unsigned long long int still_overflows;
public:
MuchData() : one("."), two("/"), three(0), four(), five(), six(-1), seven(0), still_overflows(0)
{ }
MuchData(const MuchData& rhs) : one(rhs.one), two(rhs.two), three(rhs.three), four(rhs.four), five(rhs.five), six(rhs.six), seven(rhs.seven), still_overflows(rhs.still_overflows)
{ }
MuchData(MushData&& old) : one("."), two("/"), three(0), four(), five(), six(-1), seven(0), still_overflows(0)
{ swap(*this, old); }
MuchData& operator=(MuchData old) { swap(*old, this); return *this; }
friend void swap(MuchData& left, MushData&right) {
using std::swap;
swap(left.one, right.one);
swap(left.two, right.two);
swap(left.three, right.three);
swap(left.four, right.four);
swap(left.five, right.five);
swap(left.six, right.six);
swap(left.seven, right.seven);
swap(left.still_overflows, right.still_overflows);
}
// And now we can go and do something interesting
};
With initializers written in
: one(".")
, two("/")
, three(0)
// etc.
style, this code takes even more space. And MyType and MyOtherType are probably defined with this technique as well... is there any way to reduce the amount of repetitiveness here? When new fields are added, for example, it's extremely easy to forget to add the corresponding swap(...) line, which causes a mysterious slicing.
One thing you could do is store the members in a std::tuple and provide named accessors fot them, like this:
struct MuchData {
private:
std::tuple<std::string, std::string, int, std::vector<Something>, MyType, MyOtherType, unisgned long long> data;
std::string& one() { return std::get<0>(data); }
const std::string& one() const { return std::get<0>(data); }
//etc.
};
Yes, you're trading one piece of boilerplate for another, but you will only be writing the names once; the constructor syntax will be much more concise, for example. And even if you forget to add an accessor, swap() will work just fine (as it will just swap() the tuples).
With C++1y, you can even use auto& and const auto& for the return type of the accessors, eliminating even more duplication.
You can use in-class initializers to reduce duplication between constructors that initialize fields to their standard values:
class MuchData {
std::string one{"."};
std::string two{"/"};
// ...
Then the default and move constructor become trivial.
MuchData() = default;
MuchData(MuchData&& o) { swap(*this, o); }
And you can default the copy constructor:
MuchData(const MuchData&) = default;