A while ago I wrote code resembling this:
struct Thing
{
int a,b;
};
struct Junk
{
double x;
Thing things[10];
};
Junk myjunk[] =
{
{ 23.4, { {10,20}, {30,40} } },
{ 45.6, { {55,66}, {77,88} } }
};
Originally Thing had no constructors - just a flat simple struct to hold a couple integers. myjunk[] is meant to be special hand-written data to feed into something. In real life it has dozens of lines not just two. This code compiled fine.
Then this morning I added constructors to Thing, useful elsewhere in the great scheme of things, for example, to call functions like blarf(Thing(123,456)); and create huge arrays on the heap with 'new'.
struct Thing
{
int a,b;
Thing();
Thing(int _a, int _b);
};
Now it doesn't compile. I get
Error 1 error C2552: 'Junk::things' : non-aggregates cannot be initialized with initializer list
Yes, class with constructors cannot be made this way. What is the quickest simplest fix to get this compiling?
I know C++11 allows some new ways to initialize variables, but it's not clear in this case what's best. I'm not creating a lone Thing, but an array, and that within another struct. 'Junk' will never have a constructor.
Note that there aren't any virtual methods anywhere, and never will be for Thing and Junk. I'm using Visual Studio 2010, and not sure if it's taking source to be C++11 or older C++.
Change {10, 20} to Thing(10, 20) and so forth.
If you make the constructors constexpr conditional on language version then once you upgrade to a modern compiler you will be able to have the objects initialized at compile-time again:
#if __cplusplus >= 201103L
constexpr
#endif
Thing() : a(0), b(0) {}
#if __cplusplus >= 201103L
constexpr
#endif
Thing(int a, int b) : a(a), b(b) {}
Your code is valid since C++11, so your compiler must not support that. What you can do is initialize the arrays like this:
Junk myjunk[] =
{
{ 23.4, { Thing(10,20), Thing(30,40) } },
{ 45.6, { Thing(55,66), Thing(77,88) } }
};
You can add constructor for Junk with follows
Junk(double _x, initializer_list<Thing> tl) : x(_x){
int i = 0;
for (auto & t : tl) {
things[i] = t;
++i;
if (i >= 10) {
break;
}
}
}
Related
Recent compilers, e.g. clang, complain if a function tests if "this" is NULL, as this is illegal according to the standard.
I have a program that made large use of this, and am trying to clean it up. Below are some examples that don't warn - are these safe or not? Is there a good way to get the ->toAA and ->toAB functionality behaviour that is C++ standard compliant? (Ideally without changing the code that is calling these functions, and reasonably fast - see the note below that testing this is faster in GCC 4.6.)
#include <stddef.h>
class ClassAA;
class ClassAB;
class ClassBase {
public:
enum Type {AA, AB};
Type m_type;
ClassAA* toAA();
ClassAB* toAB();
ClassBase(Type t) : m_type(t) {}
virtual ~ClassBase() {}
};
class ClassAA : public ClassBase { public: int a; ClassAA():ClassBase(AA) {} };
class ClassAB : public ClassBase { public: int b; ClassAB():ClassBase(AB) {} };
// toAA and toAB are intended to have same function,
// but toAB is significantly better performing on GCC 4.6.
inline ClassAA* ClassBase::toAA() { return dynamic_cast<ClassAA*>(this); }
inline ClassAB* ClassBase::toAB() { return (this && m_type == AB) ? static_cast<ClassAB*>(this) : NULL; }
int foo(ClassBase* bp) {
if (bp && bp->toAA()) // Legal
return -1;
if (dynamic_cast<ClassAA*>(bp)) // Legal
return -1;
if (!bp->toAA()) // No warning, is this legal?
return -1;
if (bp->toAA()->a) // No warning, is this legal?
return 10;
if (bp->toAB()->b) // Warning due to use of "this", illagal presumably
return 20;
return 0;
}
Make them free functions instead, or static members that take an argument.
Non-static member functions must be invoked on an extant object; period.
Your compiler isn't warning likely because you don't dereference this, so its detection algorithm isn't triggered. But that doesn't make the behaviour any less undefined. The compiler could be omitting the warning then sneaking off to make pancakes, for all you know.
In a function that takes several arguments of the same type, how can we guarantee that the caller doesn't mess up the ordering?
For example
void allocate_things(int num_buffers, int pages_per_buffer, int default_value ...
and later
// uhmm.. lets see which was which uhh..
allocate_things(40,22,80,...
A typical solution is to put the parameters in a structure, with named fields.
AllocateParams p;
p.num_buffers = 1;
p.pages_per_buffer = 10;
p.default_value = 93;
allocate_things(p);
You don't have to use fields, of course. You can use member functions or whatever you like.
If you have a C++11 compiler, you could use user-defined literals in combination with user-defined types. Here is a naive approach:
struct num_buffers_t {
constexpr num_buffers_t(int n) : n(n) {} // constexpr constructor requires C++14
int n;
};
struct pages_per_buffer_t {
constexpr pages_per_buffer_t(int n) : n(n) {}
int n;
};
constexpr num_buffers_t operator"" _buffers(unsigned long long int n) {
return num_buffers_t(n);
}
constexpr pages_per_buffer_t operator"" _pages_per_buffer(unsigned long long int n) {
return pages_per_buffer_t(n);
}
void allocate_things(num_buffers_t num_buffers, pages_per_buffer_t pages_per_buffer) {
// do stuff...
}
template <typename S, typename T>
void allocate_things(S, T) = delete; // forbid calling with other types, eg. integer literals
int main() {
// now we see which is which ...
allocate_things(40_buffers, 22_pages_per_buffer);
// the following does not compile (see the 'deleted' function):
// allocate_things(40, 22);
// allocate_things(40, 22_pages_per_buffer);
// allocate_things(22_pages_per_buffer, 40_buffers);
}
Two good answers so far, one more: another approach would be to try leverage the type system wherever possible, and to create strong typedefs. For instance, using boost strong typedef (http://www.boost.org/doc/libs/1_61_0/libs/serialization/doc/strong_typedef.html).
BOOST_STRONG_TYPEDEF(int , num_buffers);
BOOST_STRONG_TYPEDEF(int , num_pages);
void func(num_buffers b, num_pages p);
Calling func with arguments in the wrong order would now be a compile error.
A couple of notes on this. First, boost's strong typedef is rather dated in its approach; you can do much nicer things with variadic CRTP and avoid macros completely. Second, obviously this introduces some overhead as you often have to explicitly convert. So generally you don't want to overuse it. It's really nice for things that come up over and over again in your library. Not so good for things that come up as a one off. So for instance, if you are writing a GPS library, you should have a strong double typedef for distances in metres, a strong int64 typedef for time past epoch in nanoseconds, and so on.
(Note: post was originally tagged 'C`)
C99 onwards allows an extension to #Dietrich Epp idea: compound literal
struct things {
int num_buffers;
int pages_per_buffer;
int default_value
};
allocate_things(struct things);
// Use a compound literal
allocate_things((struct things){.default_value=80, .num_buffers=40, .pages_per_buffer=22});
Could even pass the address of the structure.
allocate_things(struct things *);
// Use a compound literal
allocate_things(&((struct things){.default_value=80,.num_buffers=40,.pages_per_buffer=22}));
You can't. That's why it is recommended to have as few function arguments as possible.
In your example you could have separate functions like set_num_buffers(int num_buffers), set_pages_per_buffer(int pages_per_buffer) etc.
You probably have noticed yourself that allocate_things is not a good name because it doesn't express what the function is actually doing. Especially I would not expect it to set a default value.
Just for completeness, you could use named arguments, when your call becomes.
void allocate_things(num_buffers=20, pages_per_buffer=40, default_value=20);
// or equivalently
void allocate_things(pages_per_buffer=40, default_value=20, num_buffers=20);
However, with the current C++ this requires quite a bit of code to be implemented (in the header file declaring allocate_things(), which must also declare appropriate external objects num_buffers etc providing operator= which return a unique suitable object).
---------- working example (for sergej)
#include <iostream>
struct a_t { int x=0; a_t(int i): x(i){} };
struct b_t { int x=0; b_t(int i): x(i){} };
struct c_t { int x=0; c_t(int i): x(i){} };
// implement using all possible permutations of the arguments.
// for many more argumentes better use a varidadic template.
void func(a_t a, b_t b, c_t c)
{ std::cout<<"a="<<a.x<<" b="<<b.x<<" c="<<c.x<<std::endl; }
inline void func(b_t b, c_t c, a_t a) { func(a,b,c); }
inline void func(c_t c, a_t a, b_t b) { func(a,b,c); }
inline void func(a_t a, c_t c, b_t b) { func(a,b,c); }
inline void func(c_t c, b_t b, a_t a) { func(a,b,c); }
inline void func(b_t b, a_t a, c_t c) { func(a,b,c); }
struct make_a { a_t operator=(int i) { return {i}; } } a;
struct make_b { b_t operator=(int i) { return {i}; } } b;
struct make_c { c_t operator=(int i) { return {i}; } } c;
int main()
{
func(b=2, c=10, a=42);
}
Are you really going to try to QA all the combinations of arbitrary integers? And throw in all the checks for negative/zero values etc?
Just create two enum types for minimum, medium and maximum number of buffers, and small medium and large buffer sizes. Then let the compiler do the work and let your QA folks take an afternoon off:
allocate_things(MINIMUM_BUFFER_CONFIGURATION, LARGE_BUFFER_SIZE, 42);
Then you only have to test a limited number of combinations and you'll have 100% coverage. The people working on your code 5 years from now will only need to know what they want to achieve and not have to guess the numbers they might need or which values have actually been tested in the field.
It does make the code slightly harder to extend, but it sounds like the parameters are for low-level performance tuning, so twiddling the values should not be perceived as cheap/trivial/not needing thorough testing. A code review of a change from
allocate_something(25, 25, 25);
...to
allocate_something(30, 80, 42);
...will likely get just a shrug/blown off, but a code review of a new enum value EXTRA_LARGE_BUFFERS will likely trigger all the right discussions about memory use, documentation, performance testing etc.
struct tester
{
int pt;
int bt=25; <--- this lines gives an error why ?
} one;
You can in C++11. You just have to enable the compile option in gcc or clang, in MSVC 2012+ it is enabled by default.
struct tester
{
int pt{0};
int bt{25};
} one;
If you have to stick with old C++, then you need a constructor as
shown in other replies
You can actually do that in versions c++11 or above. In case you need to use your current version itself you should use a constructor ( hoping you know what a constructor is, if not just google it )
This is how your code should look like
struct tester
{
int pt;
int bt;
tester() : bt(25) // Initializer list
} one;
Alternatively
struct tester
{
int pt;
int bt;
tester()
{
bt=25;
}
} one;
Use initializer list as much as possible.
Initializer list chooses the best-match constructor for the object, which is fundamentally different from assignment.
#include<valarray>
struct tester
{
std::valarray<int> pt;
const std::valarray<int> bt;
tester() : pt(25) // Initialize pt to an valarray with space for
// 25 elements, whose values are uninitialized.
// Works well but may be confusing to most
// people.
, bt(0, 25) // initialize bt to an valarray of 25 zeros
}
I want to use a two dimensional array of constant size as a class member in C++. I have problems initializing it in the constructor though.
Here are my non-working tries:
1.)
class A {
public:
int a[2][2];
A();
};
A::A() {
a = {{1,2},{2,4}};
}
yields: error: assigning to an array from an initializer list
2.)
class A {
public:
int a[2][2];
A();
};
A::A() {
int b[2][2] = {{1,2},{2,4}};
a = b;
}
yields: invalid array assignment
3.)
class A {
public:
int **a;
A();
};
A::A() {
int b[2][2] = {{1,2},{2,4}};
a = b;
}
yields: cannot convert ‘int [2][2]’ to ‘int**’ in assignment
I come from C background. I know that I could use std::vector and I am aware of the disadvantages this approach has but since this is an exercise for me I would like to know how to get it working with plain arrays. I should add that I want to work on this array later on. I want to change the stored values but not the size. Maybe that matters as well (I figured a const at the right place could help somehow?).
If you have C++11, you can use this syntax in the constructor definition:
A() : a{{1,2}, {3, 4}} {}
If you don't have C++11, you will need to stick to the wicked old ways:
A() {
a[0][0] = 1;
// etc
}
The first example also uses the constructor init-list, which should always be used to initialize members instead of intializing them in the constructor body.
various multidimensional array in constructor by example:
// int array1[1];
A() : array1{0} {}
// int array2[2][2];
A() : array2{{0}} {}
// int array3[3][3][3];
A() : array3{{{0}}} {}
Try this, it works for bidimensional array (in standard C++):
class A {
public:
int a[2][2];
A();
};
typedef struct{ int a[4]; } array_t;
A::A() {
int at[2][2] = {{1,2},{2,4}};
*(array_t*)a = *(array_t*)at;
}
Ciao
Angelo
Your first variant is extremely close to the right C++11 syntax:
A::A()
: a{{1,2},{2,4}}
{
}
To complement the previous answers (you guys are so fast):
What you were trying to do in case 1 and 2 is array assignment, not permitted, as compiler says ;
But I would like to draw your attention to your third case, that's a grave misconception, specially coming from C as you say.
Assigning to a a pointer to a local variable?
Say I have a class:
class A
{
private:
const int * const v;
public:
A();
}
I want v to be allocated in the initialization list, and I think I can define the following constructor:
A::A():v((int*)malloc(10*sizeof(int))){}
However, what about v has to be allocated in a non-standard way like the following:
cudaMalloc(&v,10*sizeof(int));
Note cudaMalloc is a CUDA API to allocate GPU memory.
(Ignoring the bigger-picture matters of overall design, exception safety etc. and focusing on the question in its most narrow scope)
Abandon the idea of doing in the initializer list and do it in the constructor body instead
A::A() : v(NULL)
{
cudaMalloc(&v, 10 * sizeof(int));
}
Or, alternatively, wrap the allocation function into your own function that returns the pointer
void *wrapped_cudaMalloc(size_t size)
{
void *m = NULL;
cudaMalloc(&m, size);
return m;
}
...
A::A() : v(wrapped_cudaMalloc(10 * sizeof(int)))
{}
Just for the sake of completeness, there's also an ugly convoluted way to do it in the initializer list without creating any wrappers by exploiting the properties of , operator
A::A() : v((cudaMalloc(&v, 10 * sizeof(int)), v))
{}
Note the additional pair of () around the comma-expression, which is needed to satisfy the initialization syntax (otherwise , will be treated as argument separator instead of comma operator).
In addition to AndreyT's excellent post (and his creative use of the comma operator), you could also wrap things up thusly:
class cudaMallocedInt
{
private:
int *v;
public:
cudaMallocedInt(int n)
{
cudaMalloc(&v, n * sizeof(int));
}
cudaMallocedInt(const cudaMallocedInt &o)
{
// Do whatever is appropriate here. Probably some sort of dance.
}
~cudaMallocedInt()
{
// Remember to cudaFree or whatever
}
operator int*()
{
return v;
}
};
class A
{
private:
cudaMallocedInt v;
public:
A()
: v(10)
{
}
...
};
Update: As Johnsyweb pointed out in comments, please be sure to adhere to the Rule of Three to make sure things don't go boom and you waste your weekends tracking down hard to debug errors instead of having fun!