The code
using namespace std;
class A
{
private:
vector<int> a;
public:
A(vector<int> x):a(x){}
string toString()
{
string s;
for (auto& element : a)
{
s += to_string(element) + " ";
}
return s;
}
};
int main()
{
A a1({1,2,3});
A a2({11,12,13});
cout << "a1 = " << a1.toString() << "\n";
cout << "a2 = " << a2.toString() << "\n";
swap(a1,a2);
cout << "a1 = " << a1.toString() << "\n";
cout << "a2 = " << a2.toString() << "\n";
return 0;
}
outputs as expected
a1 = 1 2 3
a2 = 11 12 13
a1 = 11 12 13
a2 = 1 2 3
From cplusplus.com > std::swap under complexity
Non-array: Constant: Performs exactly one construction and two assignments (although notice that each of these operations works on its own complexity).
Array: Linear in N: performs a swap operation per element.
Does it mean that std::swap when applied to a1 and a2 only swaps the pointers to the arrays [1,2,3] and [11,12,13] but does not copy any int or anything else?
What exactly does std::swap does when applied to two objects of the class A?
Assuming the std::swap copies all elements of the array, should I write a static A::swap function, using vector::swap whose time complexity is constant (from cplusplus.com > vector::swap) meaning that it only swaps the pointers?
[..] want to add a note that the semantics of std::swap is changed in C++17. So it might be a good idea to mention compiler, version of it and what standard you target.
I was hoping that a simple looking question would not have brought about complexities about C++ standards and compiler versions. I typically compile my code in C++11. For the sake of completeness here is the gcc version on my laptop.
$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/c++/4.2.1
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
There is a requirement that the type parameter to the std::swap template
is MoveConstructible and MoveAssignable. This suggests that the swap can be written roughly as (a few bits omitted)
void swap(T &a, T &b) {
T tmp{std::move(a)};
a = std::move(b);
b = std::move(tmp);
}
For your example class, it'll invoke the default move ctor/move assignment operators (edit: of A) a few times and they in turn will invoke those of std::vector.
IOW, you can expect your program to be reasonably efficient as is.
Alternatively, you can define a non-member swap function in the same namespace as A and call explicitly std::swap with vector parameters. Or call directly std::vector::swap.
Depending on your compiler and the classes/types you are using the swap function will either copy one of the classes, or use the move constructor/assignment (C++11 and upwards) (http://en.cppreference.com/w/cpp/utility/move).
Your class only consists of a vector and for vector classes this move constructor does what you refer to as simply "swapping pointers", so it will be very quick. Just be aware that implementing e.g. a copy constructor will delete the implicitly-declared move constructor which makes this 'magic' happen!! (http://en.cppreference.com/w/cpp/language/move_constructor#Implicitly-declared_move_constructor)
While looking at the swap function independently, I'm giving you an avalanche of followup-insights:
One of the most famous uses of the swap-function happens in the copy-and-swap idiom (https://progdoo.wordpress.com/2012/06/03/c11-copy-and-swap-idiom/). This works most efficiently with implemented move-constructors/assignments.
Related
This was the question: Write a program in C++ to enter two sequence separately and find total length of both sequences using constructor.
This is the program that I wrote. It runs but did I use constructors properly? Can we do this? Can we take user input in default constructors?
#include <iostream>
#include <string.h>
using namespace std;
class merge {
private:
int i;
char seq1[5];
int len, len1, len2;
char seq2[5];
public:
merge();
};
merge::merge() {
cout << "Enter first sequence: ";
cin >> seq1;
cout << "Enter second sequence: ";
cin >> seq2;
len1 = strlen(seq1);
cout << "Length of first sequence: " << len1 << "\n";
len2 = strlen(seq2);
cout << "Length of first sequence: " << len2 << "\n";
strcat (seq1, seq2);
cout << "Merged sequence: " << seq1 << "\n";
len = strlen(seq1);
cout << "Total length: " << len;
}
int main() {
merge o;
}
User input in default constructors (C++). Can this be done?
Technically yes. Constructor body is mostly the same as any other function, and I/O is possible.
Practically, I/O in a constructor would be a bad design.
So we can, but we do not do this.
Can we take user input in default constructors?
Yes you can do it, but you shouldn't.
There are many ways to explain why. For example, consider what it means to be default-constructible. From cppreference about the named requirement DefaultConstructible:
Specifies that an instance of the type can be default constructed.
Requirements
The type T satisfies DefaultConstructible if
Given
u, an arbitrary identifier
The following expressions must be valid and have their specified
effects
T u The object u is default-initialized
T u{} The object u is value-initialized or aggregate-initialized.
T() / T{} A temporary object of type T is value-initialized or aggregate-initialized.
Your merge is DefaultConstructible. But is it really?
Consider what happens when you add a second constructor:
merge::merge(std::string seq1, std::string seq2);
Now I can choose whether I want to use the default constructor to take input from user, or get the sequences from elsewhere and call the other constructor. Sounds good, no?
(It isn't. It just helps me to emphasize the problem with your default constructor in the following examples. Bear with me.)
Code that is fine with a default constructible type T, but not quite with your merge is...
example std::vector
using T = merge;
std::vector<T> v(10);
v[0] = T("1,2,3,4","4,5,6,7,8");
// ...
Because I want to avoid reallocations of the vector and because I know that T can be default constructed, I created a vector with 10 elements even though I want to create the actual elements only later. I didn't want to ask for user input 10 times when I wrote std::vector<T> v(10); but thats the only way to resize a vector that contains elements of your class.
example: std::map
std::map<int,T> m;
m[1] = T("1,2,3,4","4,5,6,7,8");
I want to add an element to the map (if it didnt exist before). std::map::operator[] tries to find an element with the given key (1). It does not find one, hence it inserts a new element with that key and a default constructed T. Then it returns a reference to that T.
I could have used insert, but I was lazy and used []. As a consequence, this code asks the user for input, but thats not what I wanted.
Here is a demo of the two issues I tried to explain above: https://godbolt.org/z/fj5qoa
Formally, your merge is default-constructible, but for most practical purposes it isn't. A default constructor is expected to construct an object in a default state. Reading user input is surprising and many types and algorithms that require that your type is default constructible will not work as expected, even though you provided a default constructor.
I recently wrote code (relevant SO answer, associated code) whose swap operation was intended to have different semantics than a combination of copy construction and copy assignment. That's where I recognized that std::sort doesn't always use std::swap or any swap function found through ADL.
For those who aren't familiar with this I put together a small example:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
namespace thing {
struct thing {
int dummy;
operator int (void) const {
return dummy;
}
thing (int value) : dummy (value) {}
thing (thing const & other) : dummy (other.dummy) {
cout << "copy " << this << " from " << &other << endl;
}
thing & operator=(thing const & other) {
dummy = other.dummy;
cout << "assign " << this << " from " << &other << endl;
}
void swap (thing & other) {
// not called
}
};
void swap (thing & lhs, thing & rhs) {
// not called
}
}
int main() {
vector<thing::thing> data = {1, 21, 42};
cout << "sorting now" << endl;
sort (begin (data), end (data), greater<int>{});
return 0;
}
Now the fact that std::sort isn't always using std::swap has been addressed multiple times here on SO:
std::sort does not always call std::swap
Does STL sort use swap or binary copy?
My question is: Has there been any consideration, in terms of a proposal or discussion, to force std::sort (and similar standard library functions) to actually use std::swap?
To me it feels a bit ... under specified ... that for the correct behavior of my code it's swap operation has to have the same semantics as the combination of copy (move) construction and copy (move) assignment.
I'm well aware of the fact that the actual implementation (using a copy followed by multiple assignments) is far more effective than applying swap to any two elements for sorting.
Definitely. See issue LWG 226 and paper N1523
A major issue is exactly what to call. ::std::swap cannot be overloaded, and unqualified swap may not be the right function. In fact, the finance industry has always been a major user of C++, and for them swap might very well be a swap.
I need a container class with API as close as possible to std::vector (except no reallocation), but whose elements' storage (and not its member variables such as size) can be specified to be allocated from an existing buffer, so that I can have all vectors' held elements in a contiguous buffer. That is, .end() of one vector points to the same element in the buffer as .front() of the next.
I don't know whether I can simply use a custom allocator with std::vector, because I can't find information on whether that allocates storage for the whole class including the size and pointer data members (in which case I can't use this approach), or just the data elements it holds (in which case I can use it).
I only need an instance's storage to be allocated once, so there's no issue with reallocation. I'm posting here to see if there's already such a container published, rather than reimplementing most of the std vector interface with iterators etc. from scratch.
Update: I unchecked the answer that was posted because it doesn't work in debug mode in Visual C++ 2012. Example with T = float:
template<class T>
inline typename ContigAlloc<T>::pointer ContigAlloc<T>::allocate(std::size_t n)
{
std::cout << "Alloc " << n << "; type match: " << std::boolalpha << std::is_same<T, float>::value << std::endl;
return reinterpret_cast<T *>(_buff.alloc(T * sizeof(n)));
}
template<class T>
inline void ContigAlloc<T>::deallocate(T *p, std::size_t n) // TODO: noexcept when VC++2013
{
std::cout << "Deall " << n << "; type match: " << std::boolalpha << std::is_same<T, float>::value << std::endl;
_buff.dealloc(p, T * sizeof(n));
}
Test:
std::vector<float, ContigAlloc<float>> vec;
vec.push_back(1.1f);
vec.push_back(1.9f);
Result in Release build is fine:
Alloc 1; type match: true
Alloc 2; type match: true
Deall 1; type match: true
Deall 2; type match: true
Result in Debug build is not fine:
Alloc 1; type match: false
Alloc 1; type match: true
Alloc 2; type match: true
Deall 1; type match: true
Deall 2; type match: true
Deall 1; type match: false
In the first call to allocate(), T = _Container_proxy
An allocator is used only to allocate storage for the elements. You can use a custom allocator for this purpose.
I stand corrected by Jon in the comments below.
I think one could implement a conforming vector such that it stored everything on the heap except a pointer. The things on the heap would be either 3 pointers, plus the allocator (if not allocator is not optimized away), or 1 pointer, the size, and the capacity (and the possibly optimized away allocator).
In practice, every single implementation of std::vector that has ever shipped in any kind of volume, including:
HP
SGI
libstdc++ (gcc)
libc++ (llvm)
Dinkumware
Microsoft
Rogue Wave
CodeWarrior
STLPort
I'm sure I'm forgetting some others...
has placed all of the supporting members within the vector class itself, and used the allocator only for allocating the data. And there seems to be little motivation to do otherwise.
So this is a de facto standard, not an official one. With the history above, it is a pretty safe one.
Note that one could not make the same claim for string, which conceptually has an identical layout. C++11 implementations of string will typically use a "short string" optimization where the allocator is not used at all for "short" strings, but rather the value is embedded within the string class. This optimization is effectively forbidden for vector by 23.2.1 General container requirements [container.requirements.general]/10:
(Unless otherwise specified) no swap() function invalidates any
references, pointers, or iterators referring to the elements of the
containers being swapped.
If I understand your question correctly, you are using vectors of fixed size.
If these sizes and the number of the vectors are compile time constants, I would suggest using std::array.
EDIT:
Just to clarify what I mean, here an example:
struct Memory {
std::array<int, 2> a1;
std::array<int, 2> a2;
} memory;
int main() {
std::array<int, 2>& a1 = memory.a1;
std::array<int, 2>& a2 = memory.a2;
a1[0] = 10;
a1[1] = 11;
a2[0] = 20;
a2[1] = 21;
int *it=&(a1[0]);
for (size_t i = 0; i < 4; ++i){
std::cout << *(it++) << ",";
}
}
Output: 10,11,20,21,
Depending on your requirements, you can also implement Memory as a singleton.
Of course it's just a guess from my side, whether this matches your current usage pattern.
Well, I got it to work in gcc and Visual C++ 2012, so I'm posting in case anyone else hits this issue. I had to add the following in my allocator class:
template<class U>
struct rebind
{
typedef typename std::conditional<std::is_same<T, U>::value, ContigAlloc<U>, std::allocator<U>>::type other;
}
template<class U>
inline operator std::allocator<U>(void) const
{
return std::allocator<U>();
}
For Visual C++2012, in Debug builds both the conditional typedef and the conversion operator seem to be needed.
This only works if the default std::allocator is stateless, which I don't think is specified in the standard.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
A standard vector can be expanded to hold one more member by doing either:
std::vector<int> v;
v.push_back(1);
or
int os = v.size();
v.resize(os+1);
v[os] = 1;
Apart from the terseness of the code using push_back(), are there any other differences? For example, is one more efficient than the other, or is the extra memory assigned differently in each case?
push_back will construct in-place, meaning it calls the copy constructor.
resize will call the default constructor, and then v[os] will call the assignment operator.
Use push_back.
As Lightness says, the allocations in either case are equivalent. See his answer for more details.
Here's an example: http://stacked-crooked.com/view?id=43766666e5c72d282bd94c05e43e8897
Memory expansion
but do they expand memory in the same way?
It is not specified explicitly in C++11 (I checked), but yes.
resize in this case is defined to "append to the container", the only logical interpretation of which makes it equivalent to insert and push_back in terms of allocation.
The back-end of the container implementation usually allocates "more than it needs" in all cases when its memory block is expanded — this is done by the standard not prohibiting it rather than the standard mandating it, and there is no wording to suggest that this is not the case for resize also.
Ultimately, then, it's completely up to the implementation, but I'd be surprised to see a difference in memory allocation rules between the two approaches on any mainstream compiler.
This testcase shows one simple example:
#include <iostream>
#include <vector>
int main() {
std::vector<int> a, b;
for(int i = 0; i != 100; ++i)
a.push_back(0);
for(int i = 0; i != 100; ++i)
b.resize(i+1);
std::cout << a.capacity() << " , " << b.capacity() << std::endl;
}
// Output from my GCC 4.7.2:
// 128 , 128
Note that this one is subtly different:
int main() {
std::vector<int> a, b;
for(int i = 0; i != 100; ++i)
a.push_back(0);
b.resize(100);
std::cout << a.capacity() << " , " << b.capacity() << std::endl;
}
// Output from my GCC 4.7.2:
// 128 , 100
This is not a fair test between the two approaches, because in the latter example we're expanding memory in different increments, and the memory backing sequence containers tends to be expanded in multiples.
Performance concerns
Anyway, as #Pubby identifies, in the resize case you'll do the implicit construction followed by the explicit assignment, which is non-optimal if you're prematurely optimising.
In the real world, the real issue here is using the wrong function for the job and writing silly code.
They are not comparable, and you should not base the decision on performance, but that being said the performance might differ quite a lot depending on the implementation.
The standard requires push_back() to have amortized constant time, which basically means that the implementation must grow the buffer for the objects following a geometric series (i.e. when growing, the new size must be proportional to the previous size by a factor F > 1).
There is no such requirement for resize(). As a matter of fact some implementations assume that if you are calling resize() it is because you have better knowledge of what the final size of the vector will be. With that in mind, those implementations will grow the buffer (if needed) to exactly the size that you are requesting, not following a geometric progression. That means that the cost of appending following this mechanism can be O(N^2), instead of O(N) for the push_back case.
Yeah, there can be a significant difference, particularly when using custom data types. Observe:
#include <iostream>
#include <vector>
struct S
{
S()
{
std::cout << "S()\n";
}
S(const S&)
{
std::cout << "S(const S&)\n";
}
S& operator = (const S&)
{
std::cout << "operator =\n";
return *this;
}
~S()
{
std::cout << "~S()\n";
}
};
int main()
{
std::vector<S> v1;
std::cout << "push_back:\n";
v1.push_back(S());
std::vector<S> v2;
std::cout << '\n' << "resize:\n";
v2.resize(1);
v2[0] = S();
std::cout << "\nend\n"; // Ignore destructors after "end" (they're not pertinent to the comparison)
}
Output:
push_back:
S()
S(const S&)
~S()
resize:
S()
S(const S&)
~S()
S()
operator =
~S()
end
~S()
~S()
push_back FTW.
Edit: In response to #Lightness Races in Orbit's comment, this is, of course, just a silly example. S obviously isn't a really "useful" struct, and if you remove all the printing statements, or simply define S as struct S {};, then of course the compiler can optimize a lot of it away.
But since when do you only use incredibly trivial data types in a program? You'll use some trivial data types, but you'll also likely use some non-trivial data types someday too. These non-trivial data types may have expensive constructors, destructors, or assignment operators (or they may not be super expensive, but they may add up if you repeatedly use resize instead of push_back), and push_back would certainly be the right choice.
resize() may allocate memory better when you need to add add few elements.
i.e
std::vector<int> v;
for(int i = 0; i < n; ++i)
v.push_back(1);
or
int os = v.size();
v.resize(os.size() + n);
for(int i = 0; i < n; ++i)
v[os + i] = 1;
But in this case it's better to use
v.reserve(os.size() + n);
and then push_back's, it'll avoid construction + assignment too, as in your case
Is there any way of doing parallel assignment in C++? Currently, the below compiles (with warnings)
#include <iostream>
int main() {
int a = 4;
int b = 5;
a, b = b, a;
std::cout << "a: " << a << endl
<< "b: " << b << endl;
return 0;
}
and prints:
a: 4
b: 5
What I'd like it to print ... if it weren't obvious, is:
a: 5
b: 4
As in, say, ruby, or python.
That's not possible. Your code example
a, b = b, a;
is interpreted in the following way:
a, (b = b), a
It does nothing. The comma operator makes it return the value of a (the right most operand). Because assignment binds tighter, b = b is in parens.
The proper way doing this is just
std::swap(a, b);
Boost includes a tuple class with which you can do
tie(a, b) = make_tuple(b, a);
It internally creates a tuple of references to a and b, and then assigned to them a tuple of b and a.
Parallel assignment is not supported in C++. Languages that support this usually treat a,b,c as a list on either side of the assignment operator, this isn't the way the comma operator works in C++. In C++, a, b evaluates a and then b, so a, b = b, a is the same as a; b = b; a;.
Or Perl. But no, it's not possible (as far as I'm aware), you need to use a temporary variable, as in:
int a = 4;
int b = 5;
{
int tmp = a;
a = b;
b = tmp;
}
FYI, internally those languages (or Perl atleast) create a temporary list { a, b }, then assign the list to the two variables. In other words, this is atleast as performant, if only a little more messy.
This question is very old – I just stumbled into it today...
...and wondered why nobody gave this answer before...
I think, it's possible to do it in C++11 similar like Python does it (under the hood):
#include <iostream>
using namespace std;
int main()
{
int a = 4, b = 5;
cout << "Before assignment: a: " << a << ", b: " << b << endl;
pair<int&, int&> ba(b, a);
ba = make_pair(a, b); // <===: (b, a) = (a, b)
cout << "After assignment : a: " << a << ", b: " << b << endl;
return 0;
}
I tried this out on ideone.com. The output was:
Before assignment: a: 4, b: 5
After assignment : a: 5, b: 4
If I remember right (I'm not a Python expert), in Python, a, b denotes a pair. (Python Doc.: 5.3. Tuples and Sequences)
Such pair can be done in C++ 11 easily e.g. with std::pair. In this case, I made a pair of references and assigned the pair of values. It works as the make_pair() loads both variables before the right pair (of values) is assigned to the left pair of references.
Scrolling again, I realize that this answer is close to the boost based solution of Johannes answer.
May be, the reason is that it didn't work in C++03. I tried in coliru.stacked-crooked.com: With -std=c++03 it yields terrible to read compiler errors – changing to -std=c++11 and it compiles and executes fine as described above.
Disclaimer
I just cannot imagine what this solution is good for nor what practical worth it may have. This is not what I tried to do. As many other answers states "It does not work." IMHO it does (spelling it right according to the C++ language)...
Or Lua...
There are tricks with C/C++, like using xor or operations, but with risk of overflow and such. Just do it the painful way, with three assignments. Not a big deal.
There is no such function in the Standard Library. You could write a set of template functions :
template <typename T1> void ParAssign(T1& Lhs_1, T1 const& Rhs1);
template <typename T1, typename T2> void ParAssign(T1& Lhs1, T2& Lhs2, T1 const& Rhs1, T2 const& Rhs2);
// etc.
ParAssign(a,b,
b,a);
That's non-trivial if there is aliasing, as in your swap example.