Suppose that there's a class called Vector, I want to overload the assignment operator for it to make it able to work like this:
a = b = c;(a,b,v are objects of Vector class)
But one thing confused me.
Suppose that there are two prototypes:
Vector & operator=(const Vector & v);
const Vector & operator=(const Vector & v);
Both two work in the case of 'a=b=c'.
So, which one is better or right?
For starters, naming your class "Vector" will probably result in frequent confusion and mixups, with std::vector. You should pick a better name. Unfortunately, "array" is also now taken...
The first one is the standard assignment operator. The assignment operator is only defined, of course, for mutable class instances, so it should return a reference to a mutable class instance.
Interesting, personally I would go with the first one, the reason for that is that the second one, is forcing constness on the result. Which might be something you don't want, also you can enforce constness externally if you want, by returning from outer functions with const etc.
At least you might be able to manually modify vector components manually.
Related
I need to sort a vector of custom type std::vector<Blah> v by Blah's integer id. I do this via std::sort(v.begin(), v.end()) with the operator < being overloaded within Blah as
bool operator< (const Blah& b) const { return (id < b.id); }
I noticed that Blah's private id cannot be declared as const int id, otherwise the type Blah does not meet the requirements for std::sort (I assume it conflicts with not being ValueSwappable?)
If id is not const everything is fine. However, I dislike the idea of the objects not having constant ids just for the requirement of rearranging their order within a vector.
Is there a way around or is this the way it is?
Is there a way around or is this the way it is?
I fear that this is the way it is. If you want to sort a vector, which is in principle an array, then you have to assign to elements when exchanging them.
At least that is what i thought, actually you can cheat a bit. Wrap your objects into an union:
template<typename T>
union ac {
// actual object
T thing;
// assignment first destructs object, then copy
// constructs a new inplace.
ac & operator=(ac<T> const & other) {
thing. ~T();
new (& thing) T(other. thing);
}
// need to provide constructor, destructor, etc.
ac(T && t) : thing (std:: forward<T>(t))
{}
ac(ac<T> const & other) : thing (other. thing) {}
~ac() {
thing. ~T();
}
// if you need them, add move assignment and constructor
};
You can then implement the (copy) assignment operator to first destruct the current object and then (copy) construct a new object from the provided inplace of the old object.
You also need to provide constructors and destructors, and of course this only works with C++11 and beyond due to limitations concerning the union members in previous language standards.
This seems to work quite nice: Live demo.
But still, I think you should first revisit some design choices, e.g. if the constant id really needs to be part of your objects
Is there a way around or is this the way it is?
So you want to update / swap the entire data of an object (including it's identity) and to keep the identity constant; the two are in conflict, because constant means "doesn't change" (and swap means "change these instances").
You have stumbled here on the two (competing) definitions of const-ness: conceptual const-ness (what the data says/means is the same) and binary const-ness (the bytes representing the data do not change). (The first definition is what lead to the introduction of mutable in the language: the ability to keep conceptual constness while breaking binary const-ness).
Your data here is conceptually constant (the interface to the data should be const) but not binary constant (you can swap values, so your bits may go away to another instance).
The canonical idea for this is to keep the data non-const internally, and provide only const public/protected access for client code.
You say:
However, I dislike the idea of the objects not having constant ids just for the requirement of rearranging their order within a vector.
Just because the identity is conceptually constant (exposed API is/should be constant), you have no actual hard requirement to keep the data constant (and should have no preference towards it, based on the API).
I made a sparse matrix class for some work I am doing. For the sparse structures, I used pointers, e.g. int* rowInd = new int[numNonZero]. For the class I wrote copy and move assignment operators and all works fine.
Reading about the move and copy semantics online, I have tangentially found an overwhelming opinion that in modern C++ I should probably not be using raw pointers. If this is the case, then I would like to modify my code to use vectors for good coding practice.
I mostly have read vectors over raw pointers. Is there any reason not to change to vectors?
If I change the data to be stored in vectors instead of new[] arrays, do I still need to manually write copy/move assignment and constructor operators for classes? Are there any important differences between vector and new[] move/copy operators?
Suppose I have a class called Levels, which contains several sparse matrix variables. I would like a function to create a vector of Levels, and return it:
vector<Levels> GetGridLevels(int &n, ... ) {
vector<Levels> grids(n);
\\ ... Define matrix variables for each Level object in grids ...
return grids;
}
Will move semantics prevent this from being an expensive copy? I would think so, but it's a vector of objects containing objects containing member vector variables, which seems like a lot...
Yes, use std::vector<T> instead of raw T *.
Also yes, the compiler will generate copy and move assignment operators for you and those will very likely have optimal performance, so don't write your own. If you want to be explicit, you can say that you want the generated defaults:
struct S
{
std::vector<int> numbers {};
// I want a default copy constructor
S(const S&) = default;
// I want a default move constructor
S(S &&) noexcept = default;
// I want a default copy-assignment operator
S& operator=(const S&) = default;
// I want a default move-assignment operator
S& operator=(S&&) noexcept = default;
};
Regarding your last question, if I understand correctly, you mean whether returning a move-aware type by-value will be efficient. Yes, it will. To get the most out of your compiler's optimizations, follow these rules:
Return by-value (not by const value, this will inhibit moving).
Don't return std::move(x), just return x (at least if your return type is decltype(x)) so not to inhibit copy elision.
If you have more than one return statement, return the same object on every path to facilitate named return value optimization (NRVO).
std::string
good(const int a)
{
std::string answer {};
if (a % 7 > 3)
answer = "The argument modulo seven is greater than three.";
else
answer = "The argument modulo seven is less than or equal to three.";
return answer;
}
std::string
not_so_good(const int a)
{
std::string answer {"The argument modulo seven is less than or equal to three."};
if (a % 7 > 3)
return "The argument modulo seven is greater than three.";
return answer;
}
For those types where you write move constructors and assignment operators, make sure to declare them noexcept or some standard library containers (notably std::vector) will refuse to use them.
Nothing related to correctness. Just be aware that constructing a vector of size n means it will initialize all of its elements, so you might prefer to construct an empty vector, then reserve(n), then push_back the elements.
No, the implicit move constructor/assignment should take care of it all - unless you suppress them.
Yes, if you don't write code to prevent the move, you'll get an efficient move from std::vector automatically.
Also, consider using an existing library such as Eigen, so you get some fairly optimized routines for free.
No. In 99% of the cases the simplest use of std::vector will do the job better and safer than raw pointers, and in the less common cases where you need to manually manage memory, these class can work with custom allocators/deallocators (for instance, if you want aligned memory for use of aligned SSE intrinsics). If you use custom allocators, the code will be potentially more complex than raw pointers, but more maintainable and less prone to memory problems.
Depending on what your other members are, and what your class does, you may need to implement move/copy assignment/ctors. But this will be much more simple. You may have to implement them yourself, but for your vectors you just need to call the corresponding operators/ctors. The code will be simple, readable, and you will have no risks of segfaults / memory leaks
Yes, but move semantics are not even necessary. Return value optimization will be responsible for the optimized copy (in fact there will be no copy). However this is compiler specific, and not guaranteed by the standard.
So I'm trying to write this class. One of the things I want to be able to do is to add two together, so I'm overloading the addition operator. But here's the thing, I don't want to return a pointer, I want to return the class "by value", so that the addition operator works without messing with pointers.
My current approach doesn't work, because the class I create goes out of scope, and the only other way I can think of is to do it with pointers. Is there any other way to do this, without calling new and allocating memory that will later have to be deleted by the user of the class?
The current code:
Polynomial operator+(const Polynomial &lhs, const Polynomial &rhs)
{
Polynomial newPoly;
newPoly.addWithOther(lhs);
newPoly.addWithOther(rhs);
return newPoly;
}
Well I figured it out. The copy constructor is called right after return is called. And the return register will take a copy of your object. Its here that any objects that are not returned will go out of scope. If you don't perform a deep copy of those objects, or in my case, a 'deep enough' copy, the members will be reallocated by the system.
Let's say I have
#include <string>
#include <vector>
using namespace std;
struct Student
{
const string name;
int grade;
Student(const string &name) : name(name) { }
};
How do I, then, keep a vector of students?
int main()
{
vector<Student> v;
// error C2582: 'operator =' function is unavailable in 'Student'
v.push_back(Student("john"));
}
Is there even a way to do this, or must I allocate all the students on the heap, and store a pointer to each of them instead?
You can't. Your type violates the "Assignable" requirement for standard containers.
ISO/IEC 14882:2003 23.1 [lib.container.requirements] / 3:
The type of objects stored in these components must meet the requirements of CopyConstructible
types (20.1.3), and the additional requirements of Assignable types.
From table 64 (Assignable requirements):
In Table 64, T is the type used to instantiate the container, t is a value of T, and u is a value of (possibly const) T.
expression: t = u; return type: T; post-condition: t is equivalent to u
In theory, a std::vector equivalent could choose to do destruction and copy construction in all cases, but that's not the contract that has been chosen. If reallocation isn't required, then using the contained type's assignment operator for things like vector::operator= and vector::assign might be significantly more efficient.
The simple answer is: you can't. If you have const member variables, then the compiler can't supply a default copy-assignment operator. However, many of the operations that std::vector provides need to make assignments, and therefore require a (public) copy-assignment operator.
Your options are:
Make name non-const.
Write your own copy-assignment operator, and think of a way to deal with "copying" a const member.
A vector often needs to move elements around. Every time a vector needs to grow when you call push_back() it reallocates memory to keep itself contiguous, and copies all the existing elements into the new space. Also if you call insert() or remove() elements must
be shifted. For vector to be able to do all that the elements must be copy-assignable, which means that the type you store in the vector must have the assignment operator defined.
Generally, if you define a class, the compiler will generate the assignment operator for that class for you. However, there are cases when the compiler is unable to do that. One of these cases is when the class has constant members (note that pointers-to-const are ok).
So, in your case, the problem is the const string name. It prevents the compiler from generating operator=(), which in turn prevents vector from compiling, even though you do not actually use assignment on its elements yourself.
One solution is to make name non-const. The other is to write your own Student::operator=(), in some way that makes sense. The third way is, as you have pointed out, to use a vector of pointers rather than a vector of objects. But then you have to handle their allocation and de-allocation.
P.S. The other case when the compiler cannot generate operator= is when your class has members that are references.
Elements of vectors must be copy-assignable, which your Student struct isn't because of the const member. Simply use string name instead of const string name.
Unless you have a specific requirement, constant members in classes are seldom useful. If you want to prevent changes to the member, make it private and add a public getter function.
Browsing through some C++ questions I have often seen comments that a STL-friendly class should implement a swap function (usually as a friend.) Can someone explain what benefits this brings, how the STL fits into this and why this function should be implemented as a friend?
For most classes, the default swap is fine, however, the default swap is not optimal in all cases. The most common example of this would be a class using the Pointer to Implementation idiom. Where as with the default swap a large amount of memory would get copied, is you specialized swap, you could speed it up significantly by only swapping the pointers.
If possible, it shouldn't be a friend of the class, however it may need to access private data (for example, the raw pointers) which you class probably doesn't want to expose in the class API.
The standard version of std::swap() will work for most types that are assignable.
void std::swap(T& lhs,T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
But it is not an optimal implementation as it makes a call to the copy constructor followed by two calls to the assignment operator.
By adding your own version of std::swap() for your class you can implement an optimized version of swap().
For example std::vector. The default implementation as defined above would be very expensive as you would need to make copy of the whole data area. Potentially release old data areas or re-allocate the data area as well as invoke the copy constructor for the contained type on each item copied. A specialized version has a very simple easy way to do std::swap()
// NOTE this is not real code.
// It is just an example to show how much more effecient swaping a vector could
// be. And how using a temporary for the vector object is not required.
std::swap(std::vector<T>& lhs,std::vector<T>& rhs)
{
std::swap(lhs.data,rhs.data); // swap a pointer to the data area
std::swap(lhs.size,rhs.size); // swap a couple of integers with size info.
std::swap(lhs.resv,rhs.resv);
}
As a result if your class can optimize the swap() operation then you should probably do so. Otherwise the default version will be used.
Personally I like to implement swap() as a non throwing member method. Then provide a specialized version of std::swap():
class X
{
public:
// As a side Note:
// This is also useful for any non trivial class
// Allows the implementation of the assignment operator
// using the copy swap idiom.
void swap(X& rhs) throw (); // No throw exception guarantee
};
// Should be in the same namespace as X.
// This will allows ADL to find the correct swap when used by objects/functions in
// other namespaces.
void swap(X& lhs,X& rhs)
{
lhs.swap(rhs);
}
If you want to swap (for example) two vectors without knowing anything about their implementation, you basically have to do something like this:
typedef std::vector<int> vec;
void myswap(vec &a, vec &b) {
vec tmp = a;
a = b;
b = tmp;
}
This is not efficient if a and b contain many elements since all those elements are copied between a, b and tmp.
But if the swap function would know about and have access to the internals of the vector, there might be a more efficient implementation possible:
void std::swap(vec &a, vec &b) {
// assuming the elements of the vector are actually stored in some memory area
// pointed to by vec::data
void *tmp = a.data;
a.data = b.data;
b.data = tmp;
// ...
}
In this implementation just a few pointers need to be copied, not all the elements like in the first version. And since this implementation needs access to the internals of the vector it has to be a friend function.
I interpreted your question as basically three different (related) questions.
Why does STL need swap?
Why should a specialized swap be implemented (i.s.o. relying on the default swap)?
Why should it be implemented as a friend?
Why does STL need swap?
The reason an STL friendly class needs swap is that swap is used as a primitive operation in many STL algorithms. (e.g. reverse, sort, partition etc. are typically implemented using swap)
Why should a specialized swap be implemented (i.s.o. relying on the default swap)?
There are many (good) answers to this part of your question already. Basically, knowing the internals of a class frequently allows you to write a much more optimized swap function.
Why should it be implemented as a friend?
The STL algorithms will always call swap as a free function. So it needs to be available as a non member function to be useful. And, since it's only beneficial to write a customized swap when you can use knowledge of internal structures to write a much more efficient swap, this means your free function will need access to the internals of your class, hence a friend.
Basically, it doesn't have to be a friend, but if it doesn't need to be a friend, there's usually no reason to implement a custom swap either.
Note that you should make sure the free function is inside the same namespace as your class, so that the STL algorithms can find your free function via Koening lookup.
One other use of the swap function is to aid exception-safe code: http://www.gotw.ca/gotw/059.htm
Efficiency:
If you've got a class that holds (smart) pointers to data then it's likely to be faster to swap the pointers than to swap the actual data - 3 pointer copies vs. 3 deep copies.
If you use a 'using std::swap' + an unqualified call to swap (or just a qualified call to boost::swap), then ADL will pick up the custom swap function, allowing efficient template code to be written.
Safety:
Pointer swaps (raw pointers, std::auto_ptr and std::tr1::shared_ptr) do not throw, so can be used to implement a non-throwing swap. A non-throwing swap makes it easier to write code that provides the strong exception guarantee (transactional code).
The general pattern is:
class MyClass
{
//other members etc...
void method()
{
MyClass finalState(*this);//copy the current class
finalState.f1();//a series of funcion calls that can modify the internal
finalState.f2();//state of finalState and/or throw.
finalState.f3();
//this only gets call if no exception is thrown - so either the entire function
//completes, or no change is made to the object's state at all.
swap(*this,finalState);
}
};
As for whether it should be implemented as friend; swapping usually requires knowledge of implementation details. It's a matter of taste whether to use a non-friend that calls a member function or to use a friend.
Problems:
A custom swap is often faster than a single assignment - but a single assignment is always faster than the default three assignment swap. If you want to move an object, it's impossible to know in a generic way whether a swap or assignment would be best - a problem which C++0x solves with move constructors.
To implement assignment operators:
class C
{
C(C const&);
void swap(C&) throw();
C& operator=(C x) { this->swap(x); return *this; }
};
This is exception safe, the copy is done via the copy constructor when you pass by value, and the copy can be optimized out by the compiler when you pass a temporary (via copy elision).