(I just noticed several posts appeared while I was writing mine, I will read them now)
(I just noticed several posts appeared while I was writing mine, I will read them now)
Yes, it is permitted for the implementation of reserve to do that. This gives latitude for implementations to make optimal decisions.Originally Posted by Galdor
Increasing allocation by a factor is different thing from calling reserve: it is an implementation optimisation made in order for say, push_back to be an amortised constant operation as is required by the standard. Calling reserve usually serves one or both of two purposes: for correctness to ensure that insertion of elements does not cause re-allocation, hence invalidating iterators, and as an optimisation where re-allocation is not desirable. Hence, it is extremely unlikely that a call to reserve will allocate a lot more space than you really need, if your call to reserve specifies exactly what you need. In fact, if you want to create the elements as soon as possible, you don't even need to call reserve: you can simply invoke the constructor that creates N elements.Originally Posted by Galdor
Refer to my post #12. If you have say, an array of average temperatures of each of the months in a year, declaring this is fine:Originally Posted by Galdor
Just that in modern C++, we might use a std::array<double, 12> instead because of the ways in which it behaves like other containers.Code:double temperatures[] = {23.4, /* ... */};
In your case, you are dealing with new double[N], in which case either you use a container or encapsulate it in a smart pointer. If not, you have to do manual memory management yourself. But, the whole ability to do manual memory management then allows RAII to be implemented, i.e., the language cannot take this away without preventing std::vector from being implemented in the first place. But since std::vector is available, we should use it when appropriate.
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
No, the code I showed in my original post is dummy source code. In reality the ArrayWrapper class wraps a double[] (or std::vector or similar) and enhances it with a whole bunch of methods and variables. The ArrayWrapper class represents a grid discretisation of a 2D field function. For instance it stores temperature measurements taken at regular intervals on a flat rectangular surface. The array label is one of the information stored in the class, but it is far from being the only one : there is also the physical size of the domain, coordinates of origin, number of ghost nodes, etc. And there is a whole bunch of methods : load, save, add, substract, compute average, compute Euclidean norm, initialise using function of cartesian coordinates, etc. Eventually the class's actual name is "DblArray" as in "Array of double" (even though it should be better called "DblField" or something)Originally Posted by laserlight
Unless std::deque allocates discontinuous chunks of memory even when there would be enough space for a contiguous allocation. However, judging by your reaction this is not case.Originally Posted by laserlight
Very nice explanation ! It is all clear for me now !Originally Posted by Elysia
Here is the new (dummy) code :
Does that look better ?Code:#include <string> #include <vector> class ArrayWrapper { private: std::string _lbl; //Label for array std::vector<double> _arr; //Wrapped array public: ArrayWrapper(void)=default; ArrayWrapper(const std::string lbl) :_lbl(lbl),_arr(30) {} ~ArrayWrapper(void)=default; ArrayWrapper (const ArrayWrapper & other) :_lbl (other._lbl), _arr (other._arr) {} // MOVE CONSTRUCTOR ArrayWrapper (ArrayWrapper&& other ) :_lbl ( std::move(other._lbl) ) ,_arr ( std::move(other._arr) ) { //Do nothing } // COPY-ASSIGNMENT OPERATOR ArrayWrapper & operator= (ArrayWrapper other ) { std::swap( _lbl , other._lbl ); std::swap( _arr , other._arr ); return *this; } // MOVE-ASSIGNMENT OPERATOR ArrayWrapper & operator= (ArrayWrapper&& other ) { std::swap( _lbl , other._lbl ); std::swap( _arr , other._arr ); return *this; } }; int main(void) { return 0; }
Several reasons:
1) std::vector is a library feature that is implemented using dynamically allocated arrays (like the result of new double[N]); it is not a magic macro.
2) The language gives you the tools to write a vector like container that may be better than std:vector for your particular project.
3) historic reasons; old code still works
4) It's not a design goal of the language to prevent people from intentionally violating what are though of as best practices
5) C compatibility
It is too clear and so it is hard to see.
A dunce once searched for fire with a lighted lantern.
Had he known what fire was,
He could have cooked his rice much sooner.
Is that better : (I'm sorry but I really love specifying (void) in the parameter lists)Originally Posted by Elysia
Code:#include <iostream> #include <string> #include <vector> class ArrayWrapper { private: std::string _lbl; //Label for array std::vector<double> _arr; //Wrapped array public: ~ArrayWrapper(void)=default; //Destructor ArrayWrapper(ArrayWrapper&& other)=default; //Move constructor ArrayWrapper & operator=(ArrayWrapper&& other)=default; //Move assignment // CONSTRUCTOR ArrayWrapper (const std::string lbl ,std::initializer_list<double> iniLs = {} ) :_lbl(lbl ) ,_arr(iniLs) { //Do nothing } // COPY CONSTRUCTOR ArrayWrapper (const ArrayWrapper & other ,const std::string lbl="" ) :_lbl(lbl=="" ? other._lbl : lbl) { _arr.clear(); std::copy( other._arr.begin() , other._arr.end() , std::back_inserter(_arr) ); } // COPY ASSIGNMENT ArrayWrapper & operator= (ArrayWrapper other ) { std::swap(_arr, other._arr); return *this; } void dispContent(void) { std::cout << "Array \"" << _lbl << "\" : "; for(const auto elem : _arr) { std::cout << elem << ", "; } std::cout << std::endl; } }; int main(void) { ArrayWrapper ArrA("Alpha", {1.0, 2.0, 3.0}); // ArrayWrapper ArrB("Beta" , {4.0, 5.0, 6.0}); //Constructor ArrayWrapper ArrC(ArrA, "Gamma"); //Copy constructor ArrayWrapper ArrD("Delta"); //Constructor ArrayWrapper ArrE(ArrayWrapper("Epsilon", {11.0, 12.0} )); //Move constructor // ArrA.dispContent(); ArrB.dispContent(); ArrC.dispContent(); ArrD.dispContent(); // ArrayWrapper ArrF = ArrayWrapper("Delta", {7.0, 8.0, 9.0}); //Move assignment ArrF.dispContent(); // ArrF = ArrB; //Copy assignment ArrF.dispContent(); // return 0; }Makes sense !Originally Posted by King Mir
I think you missed the point of Elysia's post. Your class is made up of things that C++ already knows how to copy or move. In effect, vector and string already have functions that will be called for you to do that... so you don't have to write a copy constructor or assignment operator or move constructor or move assignment. (All you're doing is writing down stuff that would happen anyway.)
Sorry for the late answer but I thought this topic was closed ; Apparently it's not…
Is this better ?
IMHO I think I still need to define a copy constructor because I want to allow the user to set a label for the newly created array that can be different from the label of the copied array.
Code:#include <iostream> #include <string> #include <vector> class ArrayWrapper { private: std::string _lbl; //Label for array std::vector<double> _arr; //Wrapped array public: ~ArrayWrapper(void)=default; //Destructor ArrayWrapper(ArrayWrapper&& other)=default; //Move constructor ArrayWrapper & operator=(ArrayWrapper&& other)=default; //Move assignment ArrayWrapper & operator=(ArrayWrapper & other)=default; //Copy assignment // CONSTRUCTOR ArrayWrapper (const std::string lbl ,std::initializer_list<double> iniLs = {} ) :_lbl(lbl ) ,_arr(iniLs) { //Do nothing } // COPY CONSTRUCTOR ArrayWrapper (const ArrayWrapper & other ,const std::string lbl="" ) :_lbl(lbl=="" ? other._lbl : lbl) { _arr.clear(); std::copy( other._arr.begin() , other._arr.end() , std::back_inserter(_arr) ); } void dispContent(void) { std::cout << "Array \"" << _lbl << "\" : "; for(const auto elem : _arr) { std::cout << elem << ", "; } std::cout << std::endl; } }; int main(void) { ArrayWrapper ArrA("Alpha", {1.0, 2.0, 3.0}); // ArrayWrapper ArrB("Beta" , {4.0, 5.0, 6.0}); //Constructor ArrayWrapper ArrC(ArrA, "Gamma"); //Copy constructor ArrayWrapper ArrD("Delta"); //Constructor ArrayWrapper ArrE(ArrayWrapper("Epsilon", {11.0, 12.0} )); //Move constructor // ArrA.dispContent(); ArrB.dispContent(); ArrC.dispContent(); ArrD.dispContent(); // ArrayWrapper ArrF = ArrayWrapper("Delta", {7.0, 8.0, 9.0}); //Move assignment ArrF.dispContent(); // ArrF = ArrB; //Copy assignment ArrF.dispContent(); // return 0; }
That's not a copy constructor then. A copy constructor is defined as a constructor that accepts a const reference to an object of its own type, as its only parameter. Is there some reason why you can't just use the default copy constructor, and then call a member function to set the new label?
What can this strange device be?
When I touch it, it gives forth a sound
It's got wires that vibrate and give music
What can this thing be that I found?
Why would he do that? That's splitting initialization.
Having a constructor that takes a reference to an object of the same type, plus another parameter is perfectly fine.
One thing you can take advantage of if you do this (in c++11) is delegating constructors; you can call the real copy constructor from your copy + label constructor, instead of listing every member variable that needs to be copied in the member initialization list.
Last edited by King Mir; 05-24-2016 at 10:44 PM.
It is too clear and so it is hard to see.
A dunce once searched for fire with a lighted lantern.
Had he known what fire was,
He could have cooked his rice much sooner.
in fact that is the only change I would really make; delegate constructors:
The reason it's like this is it forces them to pass something other then the ``other" label if that's what they want. If they don't pass anything, then this isn't called, but the default copy constructor is called instead.Code:ArrayWrapper(ArrayWrapper const &) = default; ArrayWrapper(ArrayWrapper const & other, string const & label): ArrayWrapper(other) { _lbl = label; }
What can this strange device be?
When I touch it, it gives forth a sound
It's got wires that vibrate and give music
What can this thing be that I found?
O_oI never said it wasn't. The OP keeps talking about it as if it's a copy constructor though, and thinking that he/she needs a copy constructor, and technically, it's not a copy constructor - not one that the compiler would recognize as such, anyway.
The additional parameter of the function in question has a default value.
The function is indeed the copy-constructor for the class, and any reasonably standard compiler will treat the function as such.
Soma
“Salem Was Wrong!” -- Pedant Necromancer
“Four isn't random!” -- Gibbering Mouther
I did try this but unfortunately it did not work… Clang++ returns following error :Originally Posted by whiteflags
And g++ returns :Code:main.cpp:49:10: error: call to constructor of 'ArrayWrapper' is ambiguous
Which I can understand… So I am not sure that there can be a better way than what I showed in my previous postCode:main.cpp:36:28: error: call of overloaded ‘ArrayWrapper(const ArrayWrapper&)’ is ambiguous :ArrayWrapper(other)
Or perhaps there is ?Code:// COPY CONSTRUCTOR ArrayWrapper (const ArrayWrapper & other ,const std::string lbl="" ) :_lbl(lbl=="" ? other._lbl : lbl) { _arr.clear(); std::copy( other._arr.begin() , other._arr.end() , std::back_inserter(_arr) ); }
No, a copy constructor can have default arguments, judging from cppreferenceOriginally Posted by Elkvis
and by the standardA copy constructor of class T is a non-template constructor whose first parameter is T&, const T&, volatile T&, or const volatile T&, and either there are no other parameters, or the rest of the parameters all have default values.
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&,
volatile X& or const volatile X&, and either there are no other parameters or else all other parameters
have default arguments (8.3.6). [ Example: X::X(const X&) and X::X(X&,int=1) are copy constructors.