Create shared objects in container using STL - c++

I'm trying to generate a container with shared objects.
Say, two linked list with a couple of common nodes.
L1 : {1 2 3 2 1} and L2 : {2 1}
I know if we use the Node* head and add the dynamically created objects as link, that's possible to chain common objects in both linkedlist, but is it possible to create such shared objects directly in the container ?
I was trying something like this:
std::forward_list<int> listOne{1,2,3,2,1}; // 2,1 are meant to be shared
std::forward_list<int> listTwo{1};
listTwo.insert_after(listTwo.begin(),
std::next(listOne.begin(), 3), listOne.end()); // taking 2,1 from listOne
But, that would just create another new allocation.
I'm assuming this might be prohibited due to iterator invalidation scenarios etc. producing abnormal behaviour, but I'm not sure. Is it possible any other way ?

You can use std::shared_ptr as that will keep its objects alive regardless if another std::shared_ptr pointing to the same object is deleted from a different container.
The container type isn't important for that, so you can use std::vector for example:
std::vector<std::shared_ptr<int>> v1
{
std::make_shared<int>(1),
std::make_shared<int>(2),
std::make_shared<int>(3),
std::make_shared<int>(2),
std::make_shared<int>(1),
};
std::vector<std::shared_ptr<int>> v2
{
v1[3],
v1[4],
};
std::cout << "v1" << '\n';
for(auto& sp: v1)
std::cout << *sp << '\n';
std::cout << "v2" << '\n';
for(auto& sp: v2)
std::cout << *sp << '\n';
v1.pop_back(); // remove from one container but
v1.pop_back(); // still alive and kicking in the other
std::cout << "----" << '\n';
std::cout << "v1" << '\n';
for(auto& sp: v1)
std::cout << *sp << '\n';
std::cout << "v2" << '\n';
for(auto& sp: v2)
std::cout << *sp << '\n';
Output:
v1
1
2
3
2
1
v2
2
1
----
v1
1
2
3
v2
2
1

You can create a list of shared pointers for this.
std::list<int> listInt {1,2,3,2,1};
std::list<std::shared_ptr<int>> listOne{};
std::list<std::shared_ptr<int>> listTwo{};
size_t counter = 0;
for(int elem : listInt)
{
auto ptr1 = std::make_shared<int>(elem);
listOne.push_back(ptr1);
if(counter < 3)
listTwo.push_back(std::make_shared<int>(elem));
else
listTwo.push_back(ptr1);
counter++;
}

Related

Confused with c++ swap function: std::vector<int>().swap(search_indices);

Here is the code, I am very confused. swap function is usually used to exchange the value of two parameters, like a.swap(b) or swap(a, b). What is the meaning of swap here?
std::vector<int> search_indices;
std::vector<float> distances;
int keypointNum = 0;
do
{
keypointNum++;
std::vector<int>().swap(search_indices);
std::vector<float>().swap(distances);
int id;
iterUnseg = unVisitedPtId.begin();
id = *iterUnseg;
indices->indices.push_back(features[id].ptId);
unVisitedPtId.erase(id);
tree.radiusSearch(features[id].pt, _curvature_non_max_radius, search_indices, distances);
for (int i = 0; i < search_indices.size(); ++i)
{
unVisitedPtId.erase(search_indices[i]);
}
} while (!unVisitedPtId.empty());
I have looked for how swap function works, no related explanations.
Given std::vector<int> v; definition, std::vector<int>().swap(v); clears vector v and disposes of the memory it reserved (so that v.capacity() returns 0). Starting from C++11, an arguably better way to write it is:
v.clear();
v.shrink_to_fit();
It is a trick to clear a vector and free all the allocated memory for its elements.
In these statements
std::vector<int>().swap(search_indices);
std::vector<float>().swap(distances);
there are used empty temporary created vectors, std::vector<int>() and std::vector<float>(), that are swapped with the vectors search_indices and distances.
After the calls of the member function swap the both vectors search_indices and distances become empty. In turn the temporary vectors that after the swapping contain the elements of the above two vectors will be destroyed.
This trick is used because if you will just write
search_indices.clear();
distances.clear();
the allocated memory can be preserved. That is the member function capacity can return a non-zero value.
Here is a demonstration program.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
std::cout << "v.size() = " << v.size() << '\n';
std::cout << "v.capacity() = " << v.capacity() << '\n';
std::cout << '\n';
v.clear();
std::cout << "v.size() = " << v.size() << '\n';
std::cout << "v.capacity() = " << v.capacity() << '\n';
std::cout << '\n';
std::vector<int>().swap( v );
std::cout << "v.size() = " << v.size() << '\n';
std::cout << "v.capacity() = " << v.capacity() << '\n';
}
The program output is
v.size() = 5
v.capacity() = 5
v.size() = 0
v.capacity() = 5
v.size() = 0
v.capacity() = 0
As you can see after calling the member function swap with the temporary empty vector the capacity of the vector v becomes equal tp 0.
To get the same effect using the method clear you should after calling it also to call the method shrink_to_fit(). For example
v.clear();
v.shrink_to_fit();
It seems that this is a strategy to free up memory. I wrote a test code here:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<int> test(9, 0);
std::cout <<test.size() << std::endl;
std::vector<int>().swap(test);
std::cout <<test.size() << std::endl;
cout<<"Hello World";
return 0;
}
The output is:
9
0
Hello World

Slicing a vector in C++

Is there an equivalent of list slicing [1:] from Python in C++ with vectors? I simply want to get all but the first element from a vector.
Python's list slicing operator:
list1 = [1, 2, 3]
list2 = list1[1:]
print(list2) # [2, 3]
C++ Desired result:
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2;
v2 = v1[1:];
std::cout << v2 << std::endl; //{2, 3}
This can easily be done using std::vector's copy constructor:
v2 = std::vector<int>(v1.begin() + 1, v1.end());
In C++20 it is pretty easy:
#include <span>
#include <vector>
#include <iostream>
template<int left = 0, int right = 0, typename T>
constexpr auto slice(T&& container)
{
if constexpr (right > 0)
{
return std::span(begin(std::forward<T>(container))+left, begin(std::forward<T>(container))+right);
}
else
{
return std::span(begin(std::forward<T>(container))+left, end(std::forward<T>(container))+right);
}
}
int main()
{
std::vector v{1,2,3,4,5,6,7,8,9};
std::cout << "-------------------" << std::endl;
auto v0 = slice<1,0>(v);
for (auto i : v0)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v1 = slice<0,-1>(v);
for (auto i : v1)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v2 = slice<1,3>(v);
for (auto i : v2)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v3 = slice<1,-1>(v);
for (auto i : v3)
{
std::cout << i << std::endl;
}
std::cout << "-------------------" << std::endl;
auto v4 = slice<3,3>(v);
for (auto i : v4)
{
std::cout << i << std::endl;
}
}
Result:
Program returned: 0
-------------------
2
3
4
5
6
7
8
9
-------------------
1
2
3
4
5
6
7
8
-------------------
2
3
-------------------
2
3
4
5
6
7
8
-------------------
You can also add boundary checks and other cases like negative left indices etc... but this is only an example.
Run in compiler explorer: https://godbolt.org/z/qeaxvjdbj
I know it's late but have a look at valarray and its slices. If you are using a vector of some sort of NumericType, then it's worth giving it a try.
It depends on whether you want a view or a copy.
Python's slicing for lists copies references to the elements, so it cannot be simply regarded as a view or a copy. For example,
list1 = [1, 2, 3]
list2 = list1[1:]
list2[1] = 5
print(list1) # does not change, still [1, 2, 3]
list1 = [1, 2, [3]]
list2 = list1[1:]
list2[1][0] = 5
print(list1) # changes, becomes [1, 2, [5]]
See this post for details.
DimChtz's anwer models the copy situation. If you just want a view, in C++20, you can use ranges (besides std::views::drop, std::views::take and std::views::counted are also useful):
auto v2 = v1 | std::views::drop(1); // #include <ranges>
for (auto &e: v2) std::cout << e << '\n';
or std::span:
std::span v2{v1.begin() + 1, v1.end()}; // #include <span>
for (auto &e: v2) std::cout << e << '\n';
You can follow the above answer. It's always better to know multiple ways.
int main
{
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2{v1};
v2.erase( v2.begin() );
return 0;
}
It seems that the cheapest way is to use pointer to the starting element and the number of elements in the slice. It would not be a real vector but it will be good enough for many uses.

Simple C++ Program Compiled without Optimization by GCC doesn't Generate Expected Results

Today when I tried to compile a very simple C++ program using GCC7, I met a very strange problem: the program didn't add any elements to a vector in the constructor, when compiled without optimization (e.g. -O0/-Og) by the GCC 7.2.1 from Devtoolset-7 on Red Hat Enterprise Linux 7. Only when the optimization switch was added (e.g. -O/-O1/-O2/...), the compiled binary can generated expected results. But why is this happening?
By the way:
without optimization, the binaries compiled by GCC 7.2.1 on RHEL7 and GCC 7.3.0 on Mac (Homebrew version) behaved differently: the former didn't add any elements, while the latter add 2 elements.
clang doesn't have this problem no matter the optimization is turned on or not)
The code:
#include <vector>
#include <utility>
#include <iostream>
class Container
{
std::vector<std::size_t> elements;
public:
Container() {}
Container(std::size_t n)
{
std::cout << "Creating " << n << " elements:";
for(int i; i<n; ++i)
{
std::cout << " " << i+1;
elements.push_back(i+1);
}
std::cout << '\n';
}
Container(Container& c) : elements{c.elements} {}
Container(Container&& c) : elements{std::move(c.elements)} {}
virtual ~Container() noexcept {}
Container& operator=(const Container& c)
{
if(this != &c)
{
elements = c.elements;
}
return *this;
}
Container& operator=(Container&& c)
{
if(this != &c)
{
elements = std::move(c.elements);
}
return *this;
}
void print()
{
std::cout << "Container has " << elements.size() << " elements:" << '\n';
for(auto it=elements.cbegin(); it!=elements.cend(); ++it)
{
if(it == elements.cbegin()) std::cout << *it;
else std::cout << ", " << *it;
}
if(elements.size()>0) std::cout << '\n';
}
};
Container makeContainer()
{
std::cout << "Inside makeContainer()" << '\n';
std::cout << "Before:" << '\n';
Container c(3);
c.print();
std::cout << "Temporary:" << '\n';
Container c_tmp(3);
c_tmp.print();
c = c_tmp;
std::cout << "After:" << '\n';
c.print();
return c;
};
int main()
{
Container c = makeContainer();
std::cout << "Inside main()" << '\n';
c.print();
return 0;
}
Expected output:
Inside makeContainer()
Before:
Creating 3 elements: 1 2 3
Container has 3 elements:
1, 2, 3
Temporary:
Creating 3 elements: 1 2 3
Container has 3 elements:
1, 2, 3
After:
Container has 3 elements:
1, 2, 3
Inside main()
Container has 3 elements:
1, 2, 3
Actual output:
Inside makeContainer()
Before:
Creating 3 elements:
Container has 0 elements:
Temporary:
Creating 3 elements:
Container has 0 elements:
After:
Container has 0 elements:
Inside main()
Container has 0 elements:
If you do not assign a value to a variable its state is indeterminate.
In debug mode the compiler can put the value zero to initialize indeterminate values to help with debugging. But in release this extra unasked for initialization will not happen.
for(int i; i<n; ++i) // Here you have declared `i` but not initialized it.
As a result in release mode the value is probably larger than n and thus no elements are inserted.
Note: It is UB to read the value of an initialized variable (so your whole program can do anything).

C++ - How are multi-dimensional vectors stored?

I have two questions with respect to vectors.
Let us say I have a multi-dimensional vector as follows :-
vector< vector<int> > A;
Then A[0], A[1], etc are vectors. How are the vectors stored in A? I
mean what information about the vectors A[0] and A[1] is stored in A?
And does memory re-allocation of the individual vectors such as A[2]
cause re-allocation of A as well?
Second, I tried to see how the addresses of a vector change with re-allocation. I used the following code:-
Code:
vector<int> A;
int* x ;
int* y ;
vector<int>* ad;
vector<int>* bd;
for(int i = 0 ; i < 10000; i++){
A.push_back(i);
if(i == 2){
y = &A[0];
ad = &A;
}
x = &A[0];
bd = &A;
}
I found that, the address for A does not change even though the address for A[0] changes. This is to be expected since vectors work in the background by making use of new and delete. But my question is how much information (or which information) about the vector is stored in the address &A (considering the address of &A does not change ). This is the question I have with respect to the first question as well.
I am trying to better understand how vectors work by default.
how much information (or which information) about the vector is stored in the address &A
You are correct in assuming that the data for the vector is stored separately from the vector object itself - typically, in dynamic memory.
The three things the vector object itself needs to know are
The location of the vector's data - we need this to perform the [] operator,
The size currently allocated - we need this to know when to grow the array, and
The number of elements actually placed into the vector - we need this to know where to push_back, and what to return from size().
Different implementations are possible, storing as little as a single pointer in the vector object itself. However, a typical implementation stores a pointer to the beginning of the allocated block, a pointer to the end of the active part of the allocated block, and a pointer to the end of the allocated block.
Regarding the vector's address: The address of A does not change, not because A is a vector, but because no variable's address changes while the function where you define it (or rather, the specific call of your function) is executing. I think you may be confusing A's address (ad, bd in your example) with the address of what A uses to store the elements of the vector (x and y, essentially, in your example). Vectors allocate, de-allocate or re-allocate storage.
Note that A[0] is not a variable that you defined. It is the result of the invocation of A.operator[]; so its location can change.
Regarding what's actually stored at &A: That is kind of complicated. You will need to look at the header file vector within your C++ installation. Or perhaps it would be better to have a look at the webpage for std::vector at cppreference.com. Note there's a lot of templates, and some subclassing, and some explicit template specializations, so like I said - complicated. You might want reconsider whether you really want to look under the hood just to understand how this container works as a general rule, or whether the class' public methods and sizeof() figure are sufficient for now.
I am a beginner in c++ and STL, so I just test your problem with some simple codes;
first, i have these codes:
std::vector<int> tmp;
std::cout << sizeof(tmp) << " " << tmp.size() << " " << tmp.capacity << std::endl;
the output is:
12 0 0
then, we insert some values into the vector
for(int i = 0; i != 10; ++i) tmp.push_back(i);
std::cout << sizeof(tmp) << " " << tmp.size() << " " << tmp.capacity << std::endl;
the output is
12 10 16
then, we can draw a conclusion that the vector just keep a pointer, so the sizeof() result didn't changed.
So, the answer of your question is , the child vector's push_back will not result in the reallocation of the parent vector(i don't know how to express the role of these two vectors).
There are some simple codes:
std::vector<int> v1(10);
std::vector<int> v2(10);
int i;
for(i = 0; i != 10; ++i)
v1[i] = i;
for(i = 0; i != 10; ++i)
v2[i] = i;
vv.push_back(v1);
vv.push_back(v2);
std::cout << "v1 capacity: " << v1.capacity() << " v1 size: " << v1.size() << std::endl;
std::cout << "v2 capacity: " << v2.capacity() << " v2 size: " << v2.size() << std::endl;
std::cout << "vv capacity: " << vv.capacity() << " vv size: " << vv.size() << std::endl;
for(i = 10; i != 20; ++i)
v1.push_back(i);
for(i = 10; i != 20; ++i)
v2.push_back(i);
std::cout << "v1 capacity: " << v1.capacity() << " v1 size: " << v1.size() << std::endl;
std::cout << "v2 capacity: " << v2.capacity() << " v2 size: " << v2.size() << std::endl;
std::cout << "vv capacity: " << vv.capacity() << " vv size: " << vv.size() << std::endl;
output:
v1 capacity: 10 v1 size: 10
v2 capacity: 10 v2 size: 10
vv capacity: 2 vv size: 2
v1 capacity: 20 v1 size: 20
v2 capacity: 20 v2 size: 20
vv capacity: 2 vv size: 2

Why std::make_move_iterator works on vector<string> but not on vector<int>

I was expecting that std::make_move_iterator will always move contents, but it seems not.
It looks like it is moving elements in vector<string> but not in vector<int>.
See the below code snippet:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
void moveIntVector()
{
std::cout << __func__ << std::endl;
std::vector<int> v1;
for (unsigned i = 0; i < 10; ++i) {
v1.push_back(i);
}
std::vector<int> v2(
std::make_move_iterator(v1.begin() + 5),
std::make_move_iterator(v1.end()));
std::cout << "v1 is: ";
for (auto i : v1) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "v2 is: ";
for (auto i : v2) {
std::cout << i << " ";
}
std::cout << std::endl;
}
void moveStringVector()
{
std::cout << __func__ << std::endl;
std::vector<std::string> v1;
for (unsigned i = 0; i < 10; ++i) {
v1.push_back(std::to_string(i));
}
std::vector<std::string> v2(
std::make_move_iterator(v1.begin() + 5),
std::make_move_iterator(v1.end()));
std::cout << "v1 is: ";
for (auto i : v1) {
std::cout << i << " ";
}
std::cout << std::endl;
std::cout << "v2 is: ";
for (auto i : v2) {
std::cout << i << " ";
}
std::cout << std::endl;
}
int main()
{
moveIntVector();
moveStringVector();
return 0;
}
The result is:
moveIntVector
v1 is: 0 1 2 3 4 5 6 7 8 9 # I expect this should be `0 1 2 3 4` as well!
v2 is: 5 6 7 8 9
moveStringVector
v1 is: 0 1 2 3 4
v2 is: 5 6 7 8 9
I'm on Ubuntu 14.04, gcc 4.8.2 and the code is compiled with -std=c++11
Could you explain why std::make_move_iterator have different behaviour on vector<int> and vector<string>? (Or is it a bug?)
The behaviour is expected. A move from both vectors leaves the original v1 with 5 moved-from elements in their second half.
The difference is that when the strings are moved, what is left behind is empty strings. This is because it is a very efficient way to move strings, and leave the moved-from string in a self-consistent state (Technically, they could be left to hold the value "Hello, World, nice move!", but that would incur extra cost). The bottom line is that you don't see those moved-from strings in your output.
In the case of the int vectors, there is no way to move an int that is more efficient than copying it, so they are just copied over.
If you check the sizes of the vectors, you will see the v1 have size 10 in both cases.
Here's a simplified example to illustrate that the moved from strings are left empty:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> v1{"a", "b", "c", "d", "e"};
std::vector<std::string> v2(std::make_move_iterator(v1.begin()),
std::make_move_iterator(v1.end()));
std::cout << "v1 size " << v1.size() << '\n';
std::cout << "v1: ";
for (const auto& s : v1) std::cout << s << " - ";
std::cout << '\n';
std::cout << "v2 size " << v2.size() << '\n';
std::cout << "v2: ";
for (const auto& s : v2) std::cout << s << " - ";
std::cout << '\n';
}
Output:
v1 size 5
v1: - - - - -
v2 size 5
v2: a - b - c - d - e -
When we talk about a move we are not talking about moving the object itself (it remains intact). What gets moved are its internal data. This may or may not affect the value of the object whose internal data gets moved.
That is why your int array doesn't loose its original ints. As to your string example, it still has the original std::strings just like the int example but their internal values have changed to empty strings.
It is important to remember that internally a std::string (essentially) holds a pointer to a character array. So when you copy a std::string you copy every element of the character array. A move, however, avoids doing all that copying by copying the internal pointer instead.
But if the move operation stopped there that would leave both std::strings pointing at the same character array and changing the character data pointed to by either std::string would also change the other's. So when you move a string it is not enough to merely copy the internal pointer, you have to make the internal pointer of the std::string you moved from point to a new blank character array so that it can no longer affect the string its data was moved to.
When moving an int there is no further action required after the copy of its data. There are no pointers involved so after the copy both ints contain independent data.
move constructor is like of an object works like taking a regular reference and a instruction to move things. the default move constructor tries to call the move constructor of all member variables. a user defined one... pretty much it's up to the programmer to tell it what to do.
you could program your objects to be in a undefined state after being subject to a move constructor, you can keep them unchanged(the destructor will still be called so you need to take care of that), you can keep them valid. strings will have a defined state after being subject to a move constructor.
as for your example...
int is trivially copyable and it's move constructor won't do anything but copying.
string is not trivially copyable. it has some dynamic stuff in it that the move constructor moves. and the previous one is left with a length of zero, you ARE printing them, along with the trailing "space" which you added. it's just they are the last 5 elements, at the end of what your printing and you aren't noticing it because it's equivalent to 5 trailing white spaces.