I have an issue about pushing structs allocated with new operator.
Here follows my queue declaration, my struct and the code where I allocate a new struct and try to push it in my queue:
std::queue<data_pkt> my_queue;
typedef struct data_pkt {
int sockfd;
std::string payload;
int payload_size;
} data_packet;
data_packet *data = new data_packet;
if (!data) {
printf("Failed to allocate data_packet to enqueue pkt\n");
exit(EXIT_FAILURE);
}
/* filling struct's fields... */
my_queue.push(data);
When compiling with flags -Wall -std=c++11, it gives:
error: no matching function for call to ‘std::queue<data_pkt>::push(data_packet*&)’
queue_to_internet_1.push(data);
no known conversion for argument 1 from ‘data_packet*
{aka data_pkt*}’ to ‘const value_type& {aka const data_pkt&}’
So I tried changing my queue declaration including &, so that it could accept pointers to struct, but it says:
error: template argument 1 is invalid
std::queue<&data_pkt> q;
^
QOSManager.h:57:23: error: template argument 2 is invalid
I saw that new returns a void *, so my queue should be capable of storing pointers to data_packet structs, but I don't know what I'm doing wrong.
In your code compiler produce syntax error about push of value of wrong type,
that can be fixed by:
my_queue.push(*data);
side note in C++ you not need typedef struct data_pkt{} data_packet;
you can write struct data_packet {}; and then write data_packet data;,
without struct keyword, because of C++ not C.
But your memory allocation is waste of CPU cycles,
so you can write:
data_pkt data;
my_queue.push(data);
Or to remove useless copy:
my_queue.push(data_pkt());
data_pkt &data = my_queue.back();
//fill data here
Two options to fix compilation error:
Do not use dynamic allocation as already mentioned.
Store pointers in the queue instead of structs and this is correct declaration for this std::queue<data_pkt*> my_queue;
Well, templates and std:: library is a big topic, but to quickly understand where the compiler error comes from - consider the my_queue as plain array. You either declare array of structures and set structure in each element or you declare array of pointers and set pointers.
Related
In the following code:
#include <cstring>
template <unsigned len>
struct CharArray {
CharArray() {
memset(data_, 0, len);
}
char data_[len];
};
struct Foobar {
CharArray<5> a;
CharArray<3> b;
CharArray<0> c;
};
int main() {
Foobar f;
}
The type CharArray<0> ends up having a zero-sized array as its only member. I'm aware of this being a GCC extension and unsafe practice in general. The question is not about that.
When I compile the code with gcc 10.2.0, I get the following warning:
<source>: In function 'int main()':
<source>:5:3: warning: array subscript 8 is outside array bounds of 'Foobar [1]' [-Warray-bounds]
5 | CharArray() {
| ^~~~~~~~~
<source>:18:10: note: while referencing 'f'
18 | Foobar f;
| ^
With gcc9 and earlier there's no warning.
Question: Where does the subscript 8 come from? And what is the Foobar [1] mentioned there? It looks like there's an array of one Foobars and we're trying to access element 8 in that array. Not sure how that could happen. If somebody knows the details, I'd appreciate it if you could explain it.
This happens when compiling with gcc++-10 in Ubuntu 20.04 with -O3 -Wall -Wextra as options. If I don't pass any optimization flag, there won't be any warning. Also: if I take the constructor away, the warning will also disappear.
It seems the issue is somehow related to the memset(): as avoiding it using a condition (len != 0) doesn't work it seems the compiler recognizes that the start address of CharArray<0>'s object is produced by the intialization of CharArray<3> and warns about that. This theory can be tested by conditionally not initializing CharArray<3> with memset() or specializing that type as that makes the warning go way:
CharArray() { if (len != 3) memset(data_, 0, len); }
or
template <>
struct CharArray<3> {
CharArray(): data_() { }
char data_[3];
};
The warning is probably spurious. It seems by the time the address of the zero sized array is used the compiler has "forgotten" that it was produced by accessing a different array's member. The easiest approach to avoid the warning seems to correctly initialize the data in the initializer list and not using memset() at all:
template <unsigned len>
struct CharArray {
CharArray(): data_() {}
char data_[len];
};
Doing anything to a zero length C-like array is higly suspicious. Including even defining one in my opinion.
However, you can specialise the constructor to NOT do anything to the zero length array:
template<> CharArray<0>::CharArray() {}
In order to not even define a zero sized array (which I think should not be an obstacle to anythign you might want to achieve with the class in general...), you would have to specialise the whole class. (credits to Dietmar Kühl for this addition)
I found this code in the rendering library for Quake 3. There is this function:
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`
It is being called in a loop somehwere else like this:
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
The weird part is that poly was declared as srfPoly_t *poly. What is going on
here? It is casting a srfPoly_t object to (void *) and then entering the
function as a surfaceType_t object.
Here are the declaration for the relevant structs:
typedef enum {
SF_BAD,
SF_SKIP, // ignore
SF_FACE,
SF_GRID,
SF_TRIANGLES,
SF_POLY,
SF_MD3,
SF_MD4,
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_DISPLAY_LIST,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;
typedef struct srfPoly_s {
surfaceType_t surfaceType;
qhandle_t hShader;
int fogIndex;
int numVerts;
polyVert_t *verts;
} srfPoly_t;
This is working in C, but I am trying to implement something similar in C++,
but I get the following error:
Error 1 error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
It would appear I cannot perform this type of cast in C++, or maybe there is
something else I am unable to understand. I am not very familiar with C++ and
would love to figure out how to set up something similar using it.
I am assuming this has something to do with type checking in C++, so it is not
allowed. How can I implement something similar in C++ in a safe way?
This works in C because structs are simply blocks of memory with each element in the struct laid out consecutively. This cast works because the first n bytes of a srfPoly_t struct consist of the surfaceType_t enum within that struct. The called function tries to interpret the passed-in srfPoly_t as a surfaceType_t, and succeeds because the first n bytes of the argument are, in fact, a surfaceType_t. Do not do this without a very good reason.
Casts from void*'s do not automatically occur in C++ as they do in C. You can use reinterpret_cast to explicitly cast between two different types of structs:
srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);
I am new to structure programming, and I find it quite confusing when trying to pass a structure of array in c++. I have a project to do for college, a Star Trek game. This is the sample code:
void main_menu(char,char [][sz2],int&,struct enterpriseSt*,struct klingonSt*[100]);
void combat_menu(char [][sz2],struct enterpriseSt*,int&,struct klingonSt*[100]);
struct enterpriseSt
{
int energy_level;
int damage;
int torpedo_count;
};
struct klingonSt
{
int energy_level;
int damage;
int position[2];
};
int main()
{
struct enterpriseSt enterprise;
enterprise.energy_level=energy_ent_max;
enterprise.damage=0;
enterprise.torpedo_count=10;
struct klingonSt klingon[100];
main_menu(command,galaxy,turn,&enterprise,&klingon);
return 0;
}
void main_menu(char command, char galaxy[][sz2],int& turn,struct enterpriseSt * enterprise,struct klingonSt * klingon[100])
{
combat_menu(galaxy,enterprise,turn,klingon);
}
I have two structures, enterpriseSt and klingonSt. I can pass enterprise no problem, but with klingon I am struggling. I get all kinds of errors, doesn't matter what combination I use. The current one is:
error: cannot convert ‘klingonSt (*)[100]’ to ‘klingonSt**’ for argument ‘5’ to ‘void main_menu(char, char (*)[64], int&, enterpriseSt*, klingonSt**)’
I've made such a mess with it now. Could someone please explain it to me why it works with enterprise but not with klingon?
I use g++ compiler on Ubuntu. Thanks.
Your problem is in misunderstanding the arguments parsing rules.
you think that struct klingonSt*[100] is a pointer to the array of size 100 of type struct klingonSt, but actually when argument parsing, array and function symbols that should be situated on the right of token has higher priority, than symbols on the left of expression.
So, lets first write the expression with argument name included:
struct klingonSt*var[100]
and parse it
var
is an array of size 100 (as array symbol on the right has higher priority, than pointer on the left)
of pointers
to the type struct klingonSt
so, struct klingonSt*var[100] is actually is array of size 100 of pointers to struct klingonSt.
to pass a pointer to the array of size 100 of type struct klingonSt you should change parsing precedence using parenthesis:
struct klingonSt(*var)[100]
or
struct klingonSt(*)[100]
If you change your definition, your code will compile fine.
I think you're a bit confused on passing arrays to functions. When this is done, the array decays into a pointer to the first element of the array. You can declare the parameter as an array, but the array range is ignored by the compiler, and not enforced at runtime. Thus, for this style of coding, you'd just want to pass the array as a pointer, and length as a separate parameter (I've omitted your other params for clarity):
void main_menu(enterpriseSt*, int enterpriseCount, klingonSt*, int klingonCount);
Some alternatives to consider:
Adopting a modern C++ style, and use std containers like vector/list, passing them by reference.
void main_menu(vector<enterpriseSt> & enterprises, vector<klingonSt> & klingons);
Or, using a template wrapper to pass sized local arrays implicitly:
template<size_t eCount, size_t kCount>
void main_menu(enterpriseSt (&enterprises)[eCount], klingonSt (&klingons)[kCount])
{
main_menu(enterprises, eCount, klingons, kCount);
}
The problem that
struct klingonSt * klingon[100]
is an array of 100 struct klingonSt * rather than a point to 100 struct klingonSt
use struct klingonSt klingon[][100] instead.
I am trying to make a constructor for class call, in which 4 arrays are passed as parameters. I've tried using *,&, and the array itself; however when I assign the values in the parameters to the variables in the class, I get this error :
call.cpp: In constructor ‘call::call(int*, int*, char*, char*)’:
call.cpp:4:15: error: incompatible types in assignment of ‘int*’ to ‘int [8]’
call.cpp:5:16: error: incompatible types in assignment of ‘int*’ to ‘int [8]’
call.cpp:6:16: error: incompatible types in assignment of ‘char*’ to ‘char [14]’
call.cpp:7:16: error: incompatible types in assignment of ‘char*’ to ‘char [14]’
I would appreciate your help in finding my error and helping me correct it.
here is my code:
.h file
#ifndef call_h
#define call_h
class call{
private:
int FROMNU[8];
int DESTNUM[8];
char INITIME[14];
char ENDTIME[14];
public:
call(int *,int *,char *,char *);
};
#endif
.cpp file
call:: call(int FROMNU[8],int DESTNUM[8],char INITIME[14],char ENDTIME[14]){
this->FROMNU=FROMNU;
this->DESTNUM=DESTNUM;
this->INITIME=INITIME;
this->ENDTIME=ENDTIME;
}
Raw arrays are non-assignable and generally difficult to handle. But you can put an array inside a struct, and assign or initialize that. Essentially that's what std::array is.
E.g. you can do
typedef std::array<int, 8> num_t;
typedef std::array<char, 14> time_t;
class call_t
{
private:
num_t from_;
num_t dest_;
time_t init_;
time_t end_;
public:
call_t(
num_t const& from,
num_t const& dest,
time_t const& init,
time_t const& end
)
: from_t( from ), dest_( dest ), init_( init ), end_( end )
{}
};
But this still lacks some essential abstraction, so it's merely a technical solution.
To improve things, consider what e.g. num_t really is. Is it, perhaps, a telephone number? Then model it as such.
Consider also using standard library containers std::vector and, for the arrays of char, std::string.
Passing a raw array as an argument is possible in C++.
Consider the following code:
template<size_t array_size>
void f(char (&a)[array_size])
{
size_t size_of_a = sizeof(a); // size_of_a is 8
}
int main()
{
char a[8];
f(a);
}
In C/C++ you cannot assign arrays by doing this->FROMNU=FROMNU; thus your method wont work, and is one half of your error.
The other half is that you try to assign a pointer to the array. Even if you pass arrays to a function, they decay to pointers to the first element, despite what you say in the definition.
I am working on a project that requires a class QueueArray that is an Array of Queues. It's been a while since I worked with c++ Arrays so I'm having some trouble debugging why my code is throwing errors.
I read Delete an array of queue objects for some inspiration (along with a couple hours on Google), but I am still having errors with the following code:
#include <iostream>
#include <deque>
#include <queue>
using namespace std;
class QueueArray
{
queue<int> theArray[];
QueueArray::QueueArray(int size)
{
queue<int> theArray[] = new queue<int>[size];
//theArray[] = new queue<int>[size]; //this may be closer, but also giving errors
}
};
the errors are:
warning C4200: nonstandard extension used : zero-sized array in struct/union
1> Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array
and
error C2075: 'theArray' : array initialization needs curly braces
I've read up about the 2nd error, but I can seem to figure out what I need to do to fix it.
I need it to be a variable sized array, with the variable passed to the class, which is why I can not initialize the size of the array up top, and It must be of global scope so I can use it in other functions within the class (the classes can't be passed the array through a parameter).
Later on, the queues will be of a user defined type, but we're letting them be queues of ints right now, not sure if that makes a difference. I keep seeing people suggesting the use of vectors in these cases but I don't have a choice on this one.
Any suggestions would be appreciated.
queue<int>* theArray;
not
queue<int> theArray[];
When allocating an array on the heap you get back a pointer to the start of the array, rather than an array. Thus, you want to declare your array as
queue<int>* theArray;
The use of empty brackets is allowed in some contexts but has specific meaning. It can be used when initializing a statically size array:
queue<int> theArray[] = { queue<int>(), queue<int>() /*...*/ };
creates an array of a size matching the list of initializers and it still can be empty. You can also use empty brackets in the argument list of a function in which case the use is equivalent to using pointer notation, e.g.:
int main(int ac, char* av[])
is identical to
int main(int ac, char** av)
using variable sized arrays is not possible in C++. to make your code working, use a pointer, i.e.
class QueueArray
{
queue<int> * const theArray;
QueueArray::QueueArray(int size)
: theArray (new queue<int>[size])
{ /* ... */ }
~QueueArray()
{ delete[] theArray; }
};
However, in C++ you should really avoid this and use a std::vector instead, i.e.
typedef vector<queue<int>> QueueArray;