Why do I need to have a default constructor in QVectorMyClass?
The reason why std::vector
works differently lies in the fact that in vector, raw uninitialized memory is allocated and then calls copy constructor to do the copy whenever required. This process doesn't require calling default constructor for resize()
. That's why there is no dependency as such on default constructor.
For more info, See AnT's answer here.
QVector
requires type to be default constructible because of the way the internal function realloc()
is implemented.
Source: Understanding the Qt containers
Is there still a need to provide default constructors to use STL containers?
This quote is from the C++ Programming Language, Special edition , 2005 by Bjarne Stroustrup in section 16.3.4:
If a type does not have a default constructor, it is not possible to create a vector with elements of that type, without explicitly providing the value of each element.
So it was indeed a standard requirement. It was also required that (section 17.1.4) :
To be an element of a container, an object must be of a type that allows the container implementation to copy it. The container may copy it using a copy constructor or an assignment; in either case the result of the copy must be an equivalent object.
So yes, there were "official" constructor requirementsand the library implementation were supposed to be interchangeable and not add other requirements. (Already in the very first proposal for STL in 1995, the authors tried as much as possible to clearly indicate specifications and narrow down the implementation dependent flexibility.)
You therefore had to provide a default constructor in the case where you declared other constructors:
If a user has declared a default constructor, that one will be used; otherwise, the compiler will try to generate one if needed and if the user hasn't declared other constructors.
Nowadays, this requirement is relaxed. Since C++11:
The requirements that are imposed on the elements depend on the actual operations performed on the container.
So you can define a vector for a class without default constructor, if it doesn't make sense. This for example perfectly works (online demo):
class MyClass {
public:
MyClass(int x) {}
};
int main() {
vector<MyClass> v;
MyClass test{1};
v.push_back(test);
}
But it works only as long as you don't use any operation that would need the default constructor. For instance v.resize(6);
would fail to compile.
vector resize seems to require default constructor in C++ = 11
Yes and no.
The overload that you are currently using does.
There is however a second overload where you can supply a value for the new elements - which is needed even if you know that you'll be resizing it to a smaller size.
constexpr void resize( size_type count, const value_type& value );
So either:
v.resize(2, 0);
or erase
the elements you do not want to keep. That way, you do not need to supply a value.
v.erase(std::next(v.begin(), 2), v.end());
If you want to use resize()
as the main method of resizing you could add a helper function that only uses erase()
as a fallback for types that are not default constructible.
#include <type_traits>
template <typename C>
void downsize(C& c, std::size_t size) {
if (size < c.size()) {
if constexpr (std::is_default_constructible_v<typename C::value_type>) {
c.resize(size);
} else {
c.erase(std::next(c.begin(), size), c.end());
}
}
}
Why does std::vector require move-constructors for its elements?
As implied in the comments, there isn't simply one blanket set of requirements on all objects you store in a vector. Rather, the requirements are placed on specific operations.
Although a number of operations do require than the object type be MoveConstructible
and/or MoveAssignable
, copy construction and copy assignment qualify for meeting that requirement--that is, copy constructible is basically a superset of move constructible and (likewise copy assignment vs. move assignment).
The reverse is not true though. For example, if you use the two argument constructor for a vector:
std::vector<T> vec(n, t);
...then T
must be copy constructible (because it's going to attempt to create n
copies of t
in the vector, and with move construction, it would only be able to create one item).
If you wanted to look at it as an inheritance hierarchy, you could think of copy(assignment|construction) as a derived class, and move(assignment|construction) as the base class, so you can implicitly substitute copying for moving but not vice versa.
There are quite a few cases where requirements on elements of a list
are looser than those on elements of a vector
or deque
(requirements on elements of vector
and deque
are nearly always identical, the sole exceptions of which I'm aware (thanks @yakk) being emplace_back
, which requires MoveConstructible for vector, EmplaceConstructible otherwise and the next item listed below--but note its caveat).
If you use std::vector<x> myvector(i, j);
or myvector.assign(i, j);
, (where i
and j
are iterators) then the requirements on T depend on the class of the iterators--if they're forward iterators, then T only needs to be EmplaceConstructible, otherwise T must be MoveConstructible. Caveat: although this does reflect the current wording in the standard, according to LWG 2266 the restrictions for the constructor are incorrect: they should apply regardless of the iterator category, and apply equally to vector and deque. Some future version of the standard will reflect that, but in real use that's how things already are.
In case anybody cares about why that is, and why the special treatment for non-forward iterators: the problem is that with something like an std::istream_iterator
, there's no way to know ahead of time how many items an iterator range might refer to. With something like random-access iterators, it can simply use j - i
to determine the number of items, make that much space, and insert appropriately. To work efficiently with istream_iterator
s, they normally copy the data to the end of the current collection, then after the entire range has been copied/moved into the collection, use rotate
to move them to the desired location. The extra requirement(s) support using rotate
.
There's one variant of insert
that requires elements to be swappable in addition to (Move|Copy)(Constructible|Assignable) if you're doing the insert into a vector
or deque
(the reasoning here is similar to that given above: for this variant of insert
, elements are actually inserted in one place, and then moved around to get them to where they belong).
std::vector works with classes that are not default constructible?
The requirement in C++03 is that types being stored in a container be CopyConstructible
and Assignable
(see §23.1 Container Requirements). However, in C++11 these requirements are relaxed, and tend to apply to the operations performed on the container. So a simple default construction has no requirements (see teble 96, §23.1 in C++11 standard).
As soon as you try to copy a vector, or insert elements into it, you will meet the CopyInsertable
, CopyAssignable
, EmplaceConstructible
, MoveInsertable
, MoveAssignable
etc. requirements
Initializing a std::vector with default constructor
std::vector
has a constructor declared as:
vector(size_type N, const T& x = T());
You can use it to construct the std::vector
containing N
copies of x
. The default value for x
is a value initialized T
(if T
is a class type with a default constructor then value initialization is default construction).
It's straightforward to initialize a std::vector
data member using this constructor:
struct S {
std::vector<int> x;
S() : x(15) { }
}
Can the std::vector default constructor throw an exception
It depends on the default constructor of Allocator
. The default constructor of std::vector
is declared as
vector() noexcept(noexcept(Allocator())); (since C++17)
And if std::allocator
is used then it's noexcept(true)
; i.e. won't throw exceptions.
allocator() noexcept; (since C++11)
Hence, before C++17, or if using a non-default allocator, throwing exceptions is possible.
is default enough for a c'tor d'tor of a class with vector elements only?
You don't need to write your own, but I'd modify the declaration of your constructor.
Item(const std::vector<std::string>& v, const std::vector<std::string>& e):V(v), E(e){}
Always prefer passing large object by const reference to by value. Passing object by value may causes unnecessary copy of object.
Related Topics
How to Enable_Shared_From_This of Both Parent and Derived
How to Merge Two Bst's Efficiently
C++ Best Way to Get Integer Division and Remainder
Add External Libraries to Cmakelist.Txt C++
Get Size of Terminal Window (Rows/Columns)
Image Edge Smoothing with Opencv
Is There a Compact Equivalent to Python Range() in C++/Stl
Std::Vector Reserve() and Push_Back() Is Faster Than Resize() and Array Index, Why
Should I Use Public or Private Variables
Using Declaration in Variadic Template
C++ Trying to Swap Values in a Vector
Why Was Pair Range Access Removed from C++11
Vc++ Fatal Error Lnk1168: Cannot Open Filename.Exe for Writing