Vectors of pointers to other vector's elements - c++

EI have function which takes as parameter pointer to vector:
void Function(std::vector<type>* aa)
Now inside this function I want to filter out data from that vector to another vector and I want to change data of original vector by changing values of this temporary one. Damn it's hard to understand something like:
void Function(std::vector<type>* aa)
{
std::vector<type*> temp; //to this vector I filter out data and by changning
//values of this vector I want to autmatically change values of aa vector
}
I have something like that:
void Announce_Event(std::vector<Event>& foo)
{
std::vector<Event> current;
tm current_time = {0,0,0,0,0,0,0,0,0};
time_t thetime;
thetime = time(NULL);
localtime_s(&current_time, &thetime);
for (unsigned i = 0; i < foo.size(); ++i) {
if (foo[i].day == current_time.tm_mday &&
foo[i].month == current_time.tm_mon &&
foo[i].year == current_time.tm_year+1900)
{
current.push_back(foo[i]);
}
}
std::cout << current.size() << std::endl;
current[0].title = "Changed"; //<-- this is suppose to change value.
}
That does not change original value.

I think you may be having trouble communicating your intentions, so this calls for a psychic answer.
void Func(std::vector<type> & aa)
{
std::vector<type*> temp;
// I wish <algorithm> had a 'transform_if'
for(int i=0; i<aa.size(); ++i)
{
if( some_test(aa[i]) )
temp.push_back(&aa[i])
}
// This leaves temp with pointers to some of the elements of aa.
// Only those elements which passed some_test(). Now any modifications
// to the dereferenced pointers in temp will modify those elements
// of aa. However, keep in mind that if elements are added or
// removed from aa, it may invalidate the pointers in temp.
}

Do not use a pointer to a vector, use a reference instead:
void Function(std::vector<type>& aa)
inside the function you can now access the vectors contents as usual.
void Function(std::vector<type>& aa)
{
std::vector<type>& temp = aa;
// if you now append something to temp, it is also appended to aa
aa.push_back(type());
}
I don't know why you want two references to one vector, but hey, you asked :)
EDIT: removed typo, see comments. thanx

As an aside, start formatting your code better. Messy code is difficult to understand and makes it harder for you to figure out what you're trying to do.
This will do what you want:
void Oglos_Wydarzenie(std::vector<Wydarzenie>& zmienna)
{
std::vector<Wydarzenie *> obecne;
tm AktualnyCzas = {0,0,0,0,0,0,0,0,0};
time_t czas;
czas = time(NULL);
localtime_s(&AktualnyCzas,&czas);
for (unsigned i = 0; i < zmienna.size(); ++i) {
if (zmienna[i].dzien == AktualnyCzas.tm_mday &&
zmienna[i].miesiac == AktualnyCzas.tm_mon &&
zmienna[i].rok == AktualnyCzas.tm_year+1900)
{
obecne.push_back(&zmienna[i]);
}
}
std::cout << obecne.size() << std::endl;
obecne[0]->tytul = "Changed"; //<-- this is suppose to change value.
}
You could do this with all pointers and no references at all, but then it looks much more confusing:
void Oglos_Wydarzenie(std::vector<Wydarzenie>* zmienna)
{
std::vector<Wydarzenie *> obecne;
tm AktualnyCzas = {0,0,0,0,0,0,0,0,0};
time_t czas;
czas = time(NULL);
localtime_s(&AktualnyCzas,&czas);
for (unsigned i = 0; i < zmienna->size(); ++i) {
if ((*zmienna)[i].dzien == AktualnyCzas.tm_mday &&
(*zmienna)[i].miesiac == AktualnyCzas.tm_mon &&
(*zmienna)[i].rok == AktualnyCzas.tm_year+1900)
{
obecne.push_back(&((*zmienna)[i]));
}
}
std::cout << obecne.size() << std::endl;
obecne[0]->tytul = "Changed"; //<-- this is suppose to change value.
}

Related

how return different types from function in c++?

I have a homework in c++ to make a Vector for multi data types in the same vector, I stuck where I need to return different data types and I can't change the main.
The homework ask to make the main valid:
int main()
{
Vector v;
v.add(5);
v.add(5.5f);
v.add("this");
for (int i = 0; i != v.size(); ++i) { // this code print 5 5.5 this
std::cout << v.get(i) << "\t";
}
std::cout << "Displaying an object of type Vector in different way:\n";
Integer x;
x = v.get(0);
std::cout << x << "\t"; // it prints 5
Float y;
y = v.get(1);
std::cout << y << "\t"; // it prints 5.5
String z;
z = v.get(2);
std::cout << z << "\t"; // it prints this
}
I tried what I know and I got 3 ways but still didn't fix that first I made all data pointer is char* and made a string type that worked with saving the data and cout but it stuck on return data type, I cant use template because I'm not allowed to change the main
int get(int n)
{
Node* p = head;
int i;
for (i = 0; (i < n)&&p->next; i++)
p = p->next;
if (i != n)
return NULL;
if (p->type != "int")
return NULL;
else return *((int*)p->data);
}
still I cant overload functions by just the return type, I tried to make vector have 3 pointers to data but still I stuck
int* int_;
float* float_;
string* string_;
Node* next;
string type;
Node(string type_)
I searched on internet and still not found what I want, at last I tried to make the Node template
but since the get function is on the vector and the main didn't send a type that's didn't solve the problem.
You might return wrapper with conversion operator, something like:
struct data
{
int int_ = 0;
float float_ = 0;
string string_;
operator int () const { return int_; }
operator float () const { return float_; }
operator std::string () const { return string_; }
};
const Node* get_node(int n) const
{
Node* p = head;
int i;
for (i = 0; (i < n) && p->next; i++)
p = p->next;
return p;
}
data get(int n) const
{
auto* node = get_node(n);
if (node == nullptr) throw std::out_of_range{};
return node->data;
}
Demo
If I understood correctly, what you are looking for is an heterogeneous container.
You need to create a wrapper that handle different types transparently inside your container. For your underlying type you have several options depending on your necessity.
If you know upfront the list of types that you need to support at compile type, you can use std::variant https://en.cppreference.com/w/cpp/utility/variant.
If the types that you need to support are unbounded at compile time you can use https://en.cppreference.com/w/cpp/utility/any
Finally, you can create a common interface and implement a wrapper for your supported types. The container will store a smart pointer of your objects.
UPDATE
removed suggestion on designed decision based on the C++ version
removed reference to std::vector

Return struct element from vector c++

I'm new to C++ and I'm trying to return a struct from a vector of structs by using 2 search criteria.
The function find_city is returning me everything from the defined range, regardless of whether it exists inside the vector of struct.
Here's my code:
struct cityLoc
{
int hRange;
int vRange;
int cityCode;
string cityName;
};
vector<cityLoc> cl1;
// the vector has already been preloaded with data
// function to return my struct from the vector
cityLoc find_city(int hRange, int vRange)
{
for (size_t i = 0; i < cl1.size(); i++)
{
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
{
return cl1[i];
}
}
}
int main()
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j <= 8; j++)
{
cityLoc this_city;
this_city = find_city(i, j);
cout << this_city.hRange << ", " << this_city.vRange << endl;
}
}
return 0;
}
Also, aside from this question, I was previously looking into std::find_if and didn't understand it. If I have the following code, what is the output? How do I modify it such that it returns a struct?
auto it = find_if(cl1.begin(), cl1.end(), [](cityLoc& cl) { return cl.hRange == 1; } );
You have a bug here:
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
Those = are assignments, not comparisons! Please enable compiler warnings and you won't be hurt by such obvious typos in future.
std::find_if will return the iterator to the found struct entry if it is successful, std::vector::end() otherwise. So, you should first validate the returning iterator if it is valid or not.
For example:
auto it = std::find_if( cl1.begin(), cl1.end(),
[](const cityLoc& cl) { return cl.hRange == 1; } );
if ( it == cl1.end() )
{
// ERROR: Not found! Return error code etc.
return -1;
}
// And, if found, process it here...
std::cout << it->hRange << '\n';
std::cout << it->vRange << '\n';
The criteria (predicate) part in std::find_if is a lambda expression.

openmpi/c++: defining a mpi data type for class with members of variable length (pointers pointing to malloced memory)?

i am currently learning to use openmpi, my aim is to parallelize a simple program whose code i will post bellow.
The program is for testing my concept of paralleling a much bigger program, i hope to learn all i need to know for my actual problem if i succeed with this.
Basically it is a definition of a simple c++ class for lists. A list consists of two arrays, one integer and one double. Entries with the same indicies belong together, in a way that the integer entry is some kind of list entry identifier (maybe an object ID) and the double entry is some kind of quantifier (maybe the weight if an object).
The basic purpose of the program is to add lists together (this is the task i want to parallelize). Adding works as follows: For each entry in one list it is checked if there is the same integer entry in the the other list, if so then the double entry gets added to the double entry in the other list, if there is no such entry in the other list then both the integer and the double entries gets added to the end of the list.
Basically each summand in this list addition represents a storage and each entry is a type of object with a given amount (int is the type and double is the amount), so adding two lists means putting the stuff from the second storage to the first.
The order of the list entries is irrelevant, this means that the addition of lists is not only associative but commutative too!
My plan is to add a very large number of such lists (a few billions) so parallelizing could be to let each thread add a subset of lists first and when this is finished distribute all such sublists (one for each thread) to all of the threads.
My current understanding of openmpi is that only the last step (distributing of finished sublists) needs any special non standard stuff. Basically i need a AllReduce but with a custom data type and a custom operaton.
The first problem i have is understanding how to create a fitting MPI data type. I came to the conclusion that i probably need MPI_Type_create_struct to create a struct type.
I found this site with a nice example: http://mpi.deino.net/mpi_functions/MPI_Type_create_struct.html
from which i learned a lot but the problem is, that in this case there are fixed member arrays. In my case i have lists with arbitrary sized member variables or better with pointers pointing to memory blocks of arbitrary size. So doing it like in the example would lead to creating a new MPI datatype for each list size (using fixed sized lists could help but only in this minimalistic case, but i want to learn how to do it with arbitrary sized lists are preparation for my actual problem).
So my question is: how to create a data type for this special case? What is the best way?
I even thought to maybe write some non mpi code to serialize my class/object, (which would be a lot of work for my real problem but in this example it should be easy) to a single block of bits. Then i could simply use a MPI function to distribute those blocks to all threads and then i just have to translate it back to the actual object, and then i could let each thread simply add the "number-of-threads" lists together to have the same full reduced list on all threads (because the operation is commutative it is not important if the order is the same on each thread in the end).
The problem is that i do not know which MPI function to use to distribute a such memory blocks to each thread so that in the end each thread has an array of "number-of-threads" such blocks (similar like AllReduce but with blocks).
But thats just another idea, i would like to hear from you whats the best way.
Thank you, here is my fully working example program (ignore the MPI parts thats just preparation, you can simply compile with: g++)
As you can see, i needed to create custom copy constructors because standard of the pointer members. I hope thats not a problem for MPI?
#include <iostream>
#include <cstdlib>
#if (CFG_MPI > 0)
#include <mpi.h>
#else
#define MPI_Barrier(xxx) // dummy code if not parallel
#endif
class list {
private:
int *ilist;
double *dlist;
int n;
public:
list(int n, int *il, double *dl) {
int i;
if (n>0) {
this->ilist = (int*)malloc(n*sizeof(int));
this->dlist = (double*)malloc(n*sizeof(double));
if (!ilist || !dlist) std::cout << "ERROR: malloc in constructor failed!" << std::endl;
} else {
this->ilist = NULL;
this->dlist = NULL;
}
for (i=0; i<n; i++) {
this->ilist[i] = il[i];
this->dlist[i] = dl[i];
}
this->n = n;
}
~list() {
free(ilist);
free(dlist);
ilist = NULL;
dlist = NULL;
this->n=0;
}
list(const list& cp) {
int i;
this->n = cp.n;
this->ilist = NULL;
this->dlist = NULL;
if (this->n > 0) {
this->ilist = (int*)malloc(this->n*sizeof(int));
this->dlist = (double*)malloc(this->n*sizeof(double));
if (!ilist || !dlist) std::cout << "ERROR: malloc in copy constructor failed!" << std::endl;
}
for (i=0; i<this->n; i++) {
this->ilist[i] = cp.ilist[i];
this->dlist[i] = cp.dlist[i];
}
}
list& operator=(const list& cp) {
if(this == &cp) return *this;
this->~list();
int i;
this->n = cp.n;
if (this->n > 0) {
this->ilist = (int*)malloc(this->n*sizeof(int));
this->dlist = (double*)malloc(this->n*sizeof(double));
if (!ilist || !dlist) std::cout << "ERROR: malloc in copy constructor failed!" << std::endl;
} else {
this->ilist = NULL;
this->dlist = NULL;
}
for (i=0; i<this->n; i++) {
this->ilist[i] = cp.ilist[i];
this->dlist[i] = cp.dlist[i];
}
return *this;
}
void print() {
int i;
for (i=0; i<this->n; i++)
std::cout << i << " : " << "[" << this->ilist[i] << " - " << (double)dlist[i] << "]" << std::endl;
}
list& operator+=(const list& cp) {
int i,j;
if(this == &cp) {
for (i=0; i<this->n; i++)
this->dlist[i] *= 2;
return *this;
}
double *dl;
int *il;
il = (int *) realloc(this->ilist, (this->n+cp.n)*sizeof(int));
dl = (double *) realloc(this->dlist, (this->n+cp.n)*sizeof(double));
if (!il || !dl)
std::cout << "ERROR: 1st realloc in operator += failed!" << std::endl;
else {
this->ilist = il;
this->dlist = dl;
il = NULL;
dl = NULL;
}
for (i=0; i<cp.n; i++) {
for (j=0; j<this->n; j++) {
if (this->ilist[j] == cp.ilist[i]) {
this->dlist[j] += cp.dlist[i];
break;
}
} if (j == this->n) {// no matching entry found in this
this->ilist[this->n] = cp.ilist[i];
this->dlist[this->n] = cp.dlist[i];
this->n++;
}
}
il = (int *) realloc(this->ilist, (this->n)*sizeof(int));
dl = (double *) realloc(this->dlist, (this->n)*sizeof(double));
if (!il || !dl)
std::cout << "ERROR: 2nd realloc in operator += failed!" << std::endl;
else {
this->ilist = il;
this->dlist = dl;
}
return *this;
}
};
int main(int argc, char **argv) {
int npe, myid;
#if (CFG_MPI > 0)
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD,&npe);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
#else
npe=1;
myid=0;
#endif
if (!myid) // reduce output
std::cout << "NPE = " << npe << " MYID = " << myid << std::endl;
int ilist[5] = {14,17,4,29,0};
double dlist[5] = {0.0, 170.0, 0.0, 0.0, 24.523};
int ilist2[6] = {14,117,14,129,0, 34};
double dlist2[6] = {0.5, 170.5, 0.5, 0.5, 24.0, 1.2};
list tlist(5, ilist, dlist);
list tlist2(6, ilist2, dlist2);
if (!myid) {
tlist.print();
tlist2.print();
}
tlist +=tlist2;
if (myid) tlist.print();
#if (CFG_MPI > 0)
MPI_Finalize();
#endif
return 0;
}

Create object only if some condition, otherwise return nullptr

I want to create an object only if some conditions are applied, otherwise retun nullptr. This is how I would do it in Delphi (2009+):
function GetGen(n : integer) : Generics.Collections.TList<Integer>;
var
i : integer;
begin
result := nil;
if n > 0 then begin
result := Generics.Collections.TList<Integer>.Create;
for i := 0 to n - 1 do result.Add(i);
end;
end;
procedure TestGenList(n : integer);
var
aInt : integer;
aGen : Generics.Collections.TList<Integer>;
begin
aGen := GetGen(n);
if aGen = nil then begin
WriteLn('No generic created!');
Exit;
end;
WriteLn(Format('Size: %d', [aGen.Count]));
for aInt in aGen do Write(Format('%d ', [aInt]));
aGen.Free; //will clear integers
end;
procedure TestGen
begin
TestGenList(0);
Readln;
TestGenList(5);
Readln;
end.
This is how I could do it in C++ :
unique_ptr<vector<int>> GetUniquePrtVec(int n){
if (n < 1) return(nullptr); //create only if correct input is given
unique_ptr<vector<int>> result (new vector<int>);
for (int i = 0 ; i != n; i++){
result->push_back(i);
}
return(move(result));
}
void TestPtrVec(int n){
unique_ptr<vector<int>> vec = GetUniquePrtVec(n);
if (vec == nullptr){
cout << "No vector created" << endl;
return;
}
cout << endl << vec->size() << endl;
for_each(vec->begin(), vec->end(), [](int n){cout << n << " " << endl;});
vec->clear(); //clear vector
vec.reset(nullptr);
}
void testVec3(){
TestPtrVec(0);
TestPtrVec(5);
}
My question is about the right idiom. Would you guys, experienced C++ programmers (for I am a beginner, just learning the language), do it this way? If not, then how would you do it?
Thanks.
IMHO, the best way for your example, would be to simply return the std::vector by value and simply return an empty one if the input is invalid.
std::vector<int> get_vec(int n){
std::vector<int> ret;
for(unsigned i=0; i < n; ++i)
ret.push_back(i);
return ret; // will be empty for (n < 1)
// and will be moved if (n >= 1)
}
One thing you need to learn: You don't need to explicitly std::move if you return a local variable. Just return by value. If copy elision is possible, it will do that (RVO / NRVO). If it can't for some reason, it'll first try to move it out before copying it. Note however, that a member of a local variable will not be moved automatically, aka
struct object{ std::vector<int> member; };
std::vector<int> foo(){
object o;
// ...
return o.member; // no move, no copy elision, plain old copy
}
Now, your second function can also be improved and reduced:
void try_vec(int n){
auto vec = get_vec(n); // will elide copy or simply move
for(auto& x : vec) // will not loop if vector is empty
std::cout << x << ' '; // why space and newline?
std::cout << "\n"; // don't use std::endl, it also flushes the stream
}
And from your original function:
vec->clear(); //clear vector
vec.reset(nullptr);
Is not needed, that's the whole reason for smart pointers and resource managing containers. They will destroy what they own when they go out of scope.
personally I believe that having a pointer to a vector is a bit necessary it looks as to me as if you could just return an empty vector or even throw an invalid argument error. The whole null return value is a bit of a hack and now you have to manage some memory because of it.
I personally would rather see
std::vector<int> get_vec(int n){
std::vector<int> result;
if(n < 1) return result;
result.reserve(n);
for (int i = 0 ; i != n; i++){
result.push_back(i);
}
return result;
}
or
std::vector<int> get_vec(int n){
if(n < 1) throw std::invalid_argument("n must be greater than 1");
std::vector<int> result;
result.reserve(n);
for (int i = 0 ; i != n; i++){
result.push_back(i);
}
return result;
}
void test(int n){
try{
std::vector<int> vec = get_vec(n);
catch(const std::exception& e)
{
std::cerr << "No vector created: " << e.what() << std::endl;
return;
}
//etc. . .
Seems what you need is something like boost::optional. Here is an example of its usage:
optional<char> get_async_input()
{
if ( !queue.empty() )
return optional<char>(queue.top());
else return optional<char>(); // uninitialized
}
void receive_async_message()
{
optional<char> rcv ;
// The safe boolean conversion from 'rcv' is used here.
while ( (rcv = get_async_input()) && !timeout() )
output(*rcv);
}
For more information refer to boost documentation.
Use exceptions or type erasure, returning NULL is the C way of doing things, not the C++ way.
Also you use the move semantic but you are not returning an r-value, it would not work like that.
Im a little unfamilliar with this syntax, but I think it looks okay to me. Though, why not just use pointers with the usual c+ syntax?
vector<int> GetUniquePrtVec(int n)
{
if (n < 1)
return null;
vector<int>* result = new vector<int>;
for (int i = 0 ; i != n; i++){
result->push_back(i);
}
return (result);
}
Though Ive never used a vector pointer. Generally when I create a vector I pass it to a function by reference, like this:
vector<int> myVec;
bool bSuccess = PopulateVec(n, myVec);
vector<int>* PopulateVec(int inNum, vector<int>& inVec)
{
if (inNum< 1)
return false;
for (int i = 0 ; i != inNum; i++)
{
inVec->push_back(i);
}
// inVec is "returned" by reference
return true
}

How can I return an array?

Is there any way to return an array from a function? More specifically, I've created this function:
char bin[8];
for(int i = 7; i >= 0; i--)
{
int ascii='a';
if(2^i-ascii >= 0)
{
bin[i]='1';
ascii=2^i-ascii;
}
else
{
bin[i]='0';
}
}
and I need a way to return bin[].
You can't do that but you can:
return a dynamicaly allocated array - best owned by a smart pointer so that the caller does not have to care about deallocating memory for it - you could also return something like an std::vector this way.
populate an array/vector passed to you as an argument by pointer (suggested) or a non const reference.
Your array is a local variable allocated on the stack. You should use new [] to allocate it on the heap. Then you can just say: return bin;. Beware that you will have to explicitly free it with delete [] when you are done with it.
You are really asking the wrong question. If you want to do string processing in C++, use the std::string and/or std::vector classes, not arrays of char. Your code then becomes:
vector <char> func() {
vector <char> bin(8);
for( int i = 7; i >= 0; i-- ) {
int ascii='a';
if ( 2 ^ i - ascii >= 0 ) {
bin[i] = '1';
ascii = 2^i - ascii;
}
else {
bin[i] ='0';
}
}
return bin;
}
I think your best bet is to use a vector. It can function in many ways like an array and has several upsides (length stored with type, automatic memory management).
void Calculate( std::vector<char>& bin) {
for(int i = 7; i >= 0; i--)
{
int ascii='a';
if(2^i-ascii >= 0)
{
bin.push_back('1');
ascii=2^i-ascii;
}
else
{
bin.push_back('0');
}
}
}
If you want to return a copy of the array (might make sense for small arrays) and the array has fixed size, you can enclose it in a struct;
struct ArrayWrapper {
char _bin[8];
};
ArrayWrapper func()
{
ArrayWrapper x;
// Do your stuff here using x._bin instead of plain bin
return x;
}
Or just use a std::vector as has been already suggested.
Similar implemented to #ari's answer, i want to say there is already a boost solution, boost::array solving your problem:
boost::array<char, 8> f() {
boost::array<char, 8> bin;
for(int i = 7; i >= 0; i--) {
int ascii = 'a';
if(2 ^ i-ascii >= 0) {
bin[i] = '1';
ascii = 2 ^ i-ascii;
} else {
bin[i] = '0';
}
}
}
...
boost::array<char, 8> a(f());
[I'm not sure what you want to do with that algorithm though, but note that i think you want to do 1 << i (bit-wise shift) instead of 2 ^ i which is not exponentiation in C++.]
Boost array is a normal array, just wrapped in a struct, so you lose no performance what-so-ever. It will also be available in the next C++ version as std::array, and is very easy to do yourself if you don't need the begin()/size()/data()-sugar it adds (to be a container). Just go with the most basic one:
template<typename T, size_t S>
struct array {
T t[S];
T& operator[](ptrdiff_t i) { return t[i]; }
T const& operator[](ptrdiff_t i) const { return t[i]; }
};
But as usual, use the tools already written by other people, in this case boost::array. It's also got the advantage of being an aggregate (that's why it has no user declared constructor), so it allows initializing with a brace enclosed list:
boost::array<int, 4> a = {{ 1, 2, 3, 4 }};
you need to pass array bin as an argument in your function.
array always pass by address, therefore you dont need to return any value.
it will automatically show you all changes in your main program
void FunctionAbc(char bin[], int size);
void FuncationAbc(bin, size)
{
for(int i = 7; i >= 0; i--)
{
int ascii='a';
if(2^i-ascii >= 0)
{
bin[i]='1';
ascii=2^i-ascii;
}
else
{
bin[i]='0';
}
}
}
You'll want to pass by reference, as follows:
void modifyBin(char (&bin)[8])
{
/* your function goes here and modifies bin */
}
int main()
{
char bin[8];
modifyBin(bin);
/* bin has been updated */
return 0;
}
I think that everyone else answered this one... use a container instead of an array. Here's the std::string version:
std::string foo() {
int ascii = 'a';
std::string result("00000000");
for (int i=7; i>=0; --i) {
if (2^i-ascii >= 0) {
result[i] = '1';
ascii = 2^i-ascii;
}
}
return result;
}
I'm not really sure if 2^i-ascii is want you want or not. This will be parsed as (2 ^ (i - ascii)) which is a little strange.