I have been struggling with that issue long time. It seems to be quite ineffective in C++ that array of class B created in class A have to be initialized by default constructor. Is there any way to avoid that behavior ? I implement a register of people. If I create it with count references, I get a lot of default constructor callings and it seems to be less effective that it should be. Also I have to create default constructor which is unnecessary.
When you are creating an array of objects, be it a static array (Person people[1000]) or dynamically allocated (Person* people = new Person[1000]), all 1000 objects will be created and initialized with the default constructor.
If you want to create space for the objects, but not create them just yet, you can either use a container like std::vector (which implements a dynamically sized array), or use an array of pointers, like Person* people[1000] or Person** people = new Person*[1000] - in this case, you can initialize all items with NULL to indicate empty records, and then allocate objects one by one: people[i] = new Person(/* constructor arguments here */), but you will also have to remember to delete each object individually.
I think I have the solution you are aiming for. I tested this on GCC 4.6 and it may require modification for MSVC++ for the alignment bit, but here is the sample output and the source code:
Source Code (tested with GCC 4.6):
#include <cstdio>
#include <cstring>
#include <new>
// std::alignment_of
template <typename T, std::size_t capacity>
class StaticVector
{
public:
StaticVector() : _size(0)
{
// at this point we've avoided actually initializing
// the unused capacity of the "static vector"
}
~StaticVector()
{
// deconstruct in reverse order of their addition
while (!empty())
pop_back();
}
void push_back(const T &src)
{
// at this point we initialize the unused array entry by copy
// constructing it off the passed value
new (data() + _size) T(src);
_size++;
}
void pop_back()
{
_size--;
// we manually call the deconstructor of the entry we are marking as unused
data()[_size].~T();
}
bool empty() const {return _size == 0;}
std::size_t size() const {return _size;}
// NOTE: you'd better index only into constructed data! just like an std::vector
T & operator[](int i) {return *data()[i];}
const T & operator[](int i) const {return *data()[i];}
T * data() {return reinterpret_cast<T*>(_data);}
const T * data() const {return reinterpret_cast<const T*>(_data);}
protected:
// NOTE: I only tested this on GCC 4.6, it will require some
// conditional compilation to work with MSVC and C++11
#if 1 // for GCC without c++11
char _data[sizeof(T[capacity])] __attribute__((aligned(__alignof__(T))));
#else // UNTESTED: The C++11 way of doing it?
alignas(T) char _data[sizeof(T[capacity])]; // create a suitable sized/aligned spot for the array
#endif
std::size_t _size;
};
// NOTE: lacks a default constructor, only
// constuctor that takes parameters
class B
{
public:
B(int param1, const char param2[])
{
printf("Constructing B at %08X with parameters (%i, %s)\n", (int)this, param1, param2);
x = param1;
strcpy(buffer, param2);
}
~B()
{
printf("Deconstructing B at %08X\n", (int)this);
}
// NOTE: only provided to do the printf's, the default
// copy constructor works just fine
B(const B &src)
{
printf("Copying B from %08X to %08X\n", (int)(&src), (int)this);
x = src.x;
memcpy(buffer, src.buffer, sizeof(buffer));
}
protected:
int x;
char buffer[128];
};
class A
{
public:
StaticVector<B, 8> staticVectorOfB;
};
int main()
{
printf("PROGRAM START\n");
A a;
a.staticVectorOfB.push_back(B(0, "Uno"));
a.staticVectorOfB.push_back(B(1, "Dos"));
a.staticVectorOfB.push_back(B(2, "Tres"));
printf("PROGRAM END\n");
return 0;
}
Sample Output:
PROGRAM START
Constructing B at 0022FDC4 with parameters (0, Uno)
Copying B from 0022FDC4 to 0022F9A0
Deconstructing B at 0022FDC4
Constructing B at 0022FE48 with parameters (1, Dos)
Copying B from 0022FE48 to 0022FA24
Deconstructing B at 0022FE48
Constructing B at 0022FECC with parameters (2, Tres)
Copying B from 0022FECC to 0022FAA8
Deconstructing B at 0022FECC
PROGRAM END
Deconstructing B at 0022FAA8
Deconstructing B at 0022FA24
Deconstructing B at 0022F9A0
First, you do not need to create default constructor, because otherwise the compiler will generate its code. I do not think there is a clean way to avoid calling default constructor on the object (perhaps optimizer would strip it out for the array), but there is surely a dirty one:
class B
{
};
class A
{
private:
char _array[sizeof(B)*5];
B* getB() {return (B*)_array;}
};
Then you can still use the pointer the same way as you would use fixed size array. sizeof and increment/decrement will not function though.
I guess you should not be bothered too much by "inefficiences" from default constructor. They are there for a reason. Otherwise, if default constructor really has no job to do, it should be inlined and then it will generate no overhead to execution.
How is the array, is class B inside A? Is it like B arr[size];? Instead use vector so that you can init the size in initialization and then push objects. Or dynamic array with new like below. The initfunc can create you register. Since the initfunc is called in initialization of the constructor it will be efficient.
class B
{
};
class A
{
B *barray;
B* initfunc()
{
B* tmp = new B[5];
//init elements of B
return tmp;
}
public:
A():barray(initfunc())
{
}
~A()
{
delete[] barray;
}
};
//the code is not exception safe, vector recommended.
Related
For a user defined class which already has an explicit constructor accepting a single argument, Is it possible to implement the Conversion Constructor behavior in some other way.
The class in question -
class Foo
{
explicit Foo(int size);
}
Is it possible to make this code still valid -
Foo a = 3;
No. This is not possible. A constructor can only be used for one purpose, and you can't have two constructors with the same arguments that do different things.
If Foo were an array of ints like you said in your comments, it probably would be a poor design choice to have a constructor with a single argument that fills the first element of the array. It's poor design for a couple of reasons:
How do you know what size the array is going to be when Foo is initialized? Even if there were some default value, it would be a non-obvious implementation.
It's confusing. You should use the element of least surprise when designing code. I've never, ever seen a class that wraps an array have a single argument constructor that fills it's first element. It doesn't really make sense.
In C++ 11, you can use an initializer list as the second constructor.
#include <initializer_list>
#include <cstring>
class Foo {
private:
int* arr;
size_t len;
public:
explicit Foo(size_t size)
: len(size) {
arr = new int[len];
}
Foo(std::initializer_list<int> list) // Initializer list constructor
: len(list.size()) {
arr = new int[len];
size_t pos = 0;
for(auto it = list.begin(), e = list.end(); it != e; ++it) {
arr[pos++] = *it; // copy the list into your array
}
}
Foo(const Foo& other)
: len(other.len) {
arr = new int[len];
memcpy(arr, other.arr, len * sizeof*arr);
}
Foo& operator=(const Foo& other) {
if (&other != this) {
delete[] arr;
len = other.len;
arr = new int[len];
memcpy(arr, other.arr, len * sizeof*arr);
}
return *this;
}
~Foo() {
delete[] arr;
}
};
That way, you could use it like this to initialize 1 element:
Foo a = { 3 };
Or like this to create an array with "3" ints:
Foo a(3);
Or even create the whole array at once:
Foo a = { 3, 7, 10, 12, 13 };
I realize that you just used an int-array as an example, but this just shows that there are often better ways of designing code then what you propose.
Yes. Right after the definition of class Foo simply write:
struct Bar {
Bar(int){};
};
#define Foo Bar
and the required code now compiles, and calls a conversion constructor.
This seems like a bad idea, but it is possible.
I'm facing a problem using VC++ and Debug CRT with a DLL in development.
I have a struct like that, holding some references.
struct DATA
{
TA*& a;
TB*& b;
TC*& c;
TD*& d;
char** chars;
int num_chars;
private:
// because:
// DATA a;
// DATA b;
// a = b; // is impossible
DATA& operator=(const DATA&); // append " = delete;" for C++11
// Default ctor (private because struct should be manually constructed using malloc)
DATA(TA*& a, TB*& b, TC*& c, TD*& d)
: a(a),
b(b),
c(c),
d(d),
chars(NULL),
num_chars(0)
{}
};
and construct it like that:
DATA*& Get()
{
static struct DATA *data = (struct DATA*)malloc(sizeof(struct DATA));
return data;
}
now it should hold uninitialized ref-to-ptrs, which I want to init by:
void func(TA* a, TB* b, TC* c, TD* d)
{
Get()->a = a;
Get()->b = b;
Get()->c = c;
Get()->d = d;
...
}
which works for everything, but ref-to-ptrs..
I'm getting a INVALID_POINTER_WRITE_FILL_PATTERN_cdcdcdcd on the first Get()->a = a; when I do !analyze -v -f using WinDbg (in a remote Kernel Debugging "kd" instance)
Thanks for your help! :)
Edit: Solution
Solution is to use the points from the correct answer.
Making the c'tor public is necessary:
struct DATA
{
TA*& a;
TB*& b;
TC*& c;
TD*& d;
char** chars;
int num_chars;
// Default ctor
DATA(TA*& a, TB*& b, TC*& c, TD*& d)
: a(a),
b(b),
c(c),
d(d),
chars(NULL),
num_chars(0)
{}
private:
// because:
// DATA a;
// DATA b;
// a = b; // is impossible
DATA& operator=(const DATA&); // append " = delete;" for C++11
};
then using placement newto construct the struct:
DATA*& Get(...)
{
// ... some stuff, overloading, other init-method etc. to init and construct like:
static struct DATA *data =
new(malloc(sizeof(struct DATA))) DATA(...); // At least assign ALL references in the c'tor
return data;
}
then use it and maybe assign everything that's no reference:
void func(TA* a, TB* b, TC* c, TD* d)
{
Get(a, b, c, d);
Get()->chars = ...
...
}
free'ing the whole thing needs to be done explicitly by calling the d'tor and free , because we use placement new:
data->~DATA();
free(data);
You cannot declare references without initializing them. Your struct has no default constructor, since you explicitly declare a non-default constructor. Just allocating malloc is not sufficient to create a valid DATA object, as it is a non-POD type.
Just go ahead and try declaring a real default constructor (i.e., DATA() {}), and you'll see that this won't work because of the reference members. If you want to use malloc to allocate non-POD objects, you'll have to use a placement new.
Note that malloc() returns uninitialized memory. C++ objects need to be constructed. The way to get an object into uninitialized memory is to use placement new (this code also adds clean-up):
#include <new>
DATA*& Get()
{
static DATA *data = new(malloc(sizeof(struct DATA))) DATA(...);
static std::unique_ptr<DATA, void(*)(DATA*)> clean(data,
[](DATA* d){
d->~DATA();
free(data);
});
return data;
}
There is no way in C++ to reseat references, i.e., they need to be set during construction. Personally, I wouldn't use malloc() but rather a suitable allocation anyway:
static DATA* data(new DATA(...));
... or, as Jarod42 pointed out, actually
static DATA data(...);
return &data;
Is there a standard container for a sequence of fixed length, where that length is determined at runtime. Preferrably, I'd like to pass an argument to the constructor of each sequence element, and use that argument to initialize a const member (or a reference). I'd also like to obtain the sequence element at a given index in O(1). It seems to me that all of my requirements cannot be met at the same time.
I know std::array has fixed length, but that length has to be known at compile-time.
std::vector has dynamic size, and allows passing contructor arguments using emplace. Although you can reserve memory to avoid actual reallocations, the type still has to be movable to theoretically allow such reallocations, which e.g. prevents const members.
Then there is std::list and std::forward_list, which don't require a movable type, but which are still resizable and will perform rather poorly under random-access patterns. I also feel that there might be considerable overhead associated with such lists, since each list node will likely be allocated separately.
Strangely enough, std::valarray is my best bet so far, since it has a fixed length and won't resize automatically. Although there is a resize method, your type won't have to be movable unless you actually call that method. The main deficit here is the lack for custom constructor arguments, so initializing const members isn't possible with this approach.
Is there some alternative I missed? Is there some way to adjust one of the standard containers in such a way that it satisfies all of my requirements?
Edit: To give you a more precise idea of what I'm trying to do, see this example:
class A {
void foo(unsigned n);
};
class B {
private:
A* const a;
const unsigned i;
public:
B(A* aa) : a(aa), i(0) { }
B(A* aa, unsigned ii) : a(aa), i(ii) { }
B(const std::pair<A*, unsigned>& args) : B(args.first, args.second) { }
B(const B&) = delete;
B(B&&) = delete;
B& operator=(const B&) = delete;
B& operator=(B&&) = delete;
};
void A::foo(unsigned n) {
// Solution using forward_list should be guaranteed to work
std::forward_list<B> bs_list;
for (unsigned i = n; i != 0; --i)
bs_list.emplace_front(std::make_pair(this, i - 1));
// Solution by Arne Mertz with single ctor argumen
const std::vector<A*> ctor_args1(n, this);
const std::vector<B> bs_vector(ctor_args1.begin(), ctor_args1.end());
// Solution by Arne Mertz using intermediate creator objects
std::vector<std::pair<A*, unsigned>> ctor_args2;
ctor_args2.reserve(n);
for (unsigned i = 0; i != n; ++i)
ctor_args2.push_back(std::make_pair(this, i));
const std::vector<B> bs_vector2(ctor_args2.begin(), ctor_args2.end());
}
Theoretically vector has the properties you need. As you noted, actions that possibly do assignments to the contained type, including especially any sequence modifications (empace_back, push_back, insert etc.) are not supported if the elements are noncopyable and/or nonassignable. So to create a vector of noncopyable elements, you'd have to construct each element during vector construction.
As Steve Jessop points out in his answer, if you define the vector const in the first place you won't even be able to call such modifying actions - and of course the elements remain unchanged as well.
If I understand correctly, you have only a sequence of constructor arguments, not the real object sequence. If it's only one argument and the contained type has a corresponding constructor, things shoule be easy:
struct C
{
const int i_;
C(int i) : i_(i) {}
};
int main()
{
const std::vector<C> theVector { 1, 2, 3, 42 };
}
If the constructor is explicit, you have to make a list first or explicitly construct the objects in the initializer-list:
int main()
{
auto list = { 1, 2, 3, 4 };
const std::vector<C> theVector (std::begin(list), std::end(list));
const std::vector<C> anotherVector { C(1), C(44) };
}
If it's more than just one argument per constructed object, consider a intermediate creator object:
struct C
{
const int i_;
C(int i, int y) : i_(i+y) {}
};
struct CCreator
{
int i; int y;
explicit operator C() { return C(i,y); }
};
int main()
{
const std::vector<CCreator> ctorArgs = { {1,2}, {3,42} };
const std::vector<C> theVector { begin(ctorArgs), end(ctorArgs) };
}
I think const std::vector<T> has the properties you ask for. Its elements aren't actually defined with const, but it provides a const view of them. You can't change the size. You can't call any of the member functions that need T to be movable, so for normal use they won't be instantiated (they would be if you did an extern class declaration, so you can't do that).
If I'm wrong, and you do have trouble because T isn't movable, try a const std::deque<T> instead.
The difficulty is constructing the blighter -- in C++11 you can do this with an initializer list, or in C++03 you can construct a const vector from a non-const vector or from anything else you can get iterators for. This doesn't necessarily mean T needs to be copyable, but there does need to be a type from which it can be constructed (perhaps one you invent for the purpose) .
Add a level of indirection by using a std::shared_ptr. The shared pointer can be copied and assigned as usual, but without modifying the object that is pointed to. This way you should not have any problems, as the following example shows:
class a
{
public:
a(int b) : b(b) { }
// delete assignment operator
a& operator=(a const&) = delete;
private:
// const member
const int b;
};
// main
std::vector<std::shared_ptr<a>> container;
container.reserve(10);
container.push_back(std::make_shared<a>(0));
container.push_back(std::make_shared<a>(1));
container.push_back(std::make_shared<a>(2));
container.push_back(std::make_shared<a>(3));
Another advantage is the function std::make_shared which allows you to create your objects with an arbitrary number of arguments.
Edit:
As remarked by MvG, one can also use std::unique_ptr. Using boost::indirect_iterator the indirection can be removed by copying the elements into a new vector:
void A::foo(unsigned n)
{
std::vector<std::unique_ptr<B>> bs_vector;
bs_vector.reserve(n);
for (unsigned i = 0; i != n; ++i)
{
bs_vector.push_back(std::unique_ptr<B>(new B(this, i)));
}
typedef boost::indirect_iterator<std::vector<std::unique_ptr<B>>::iterator> it;
// needs copy ctor for B
const std::vector<B> bs_vector2(it(bs_vector.begin()), it(bs_vector.end()));
// work with bs_vector2
}
I also encounter this problem, the use case in my code is to provide a thread-safe vector, the elements number is fixed and are atomic numbers. I have read all the great answers here. I think we may also consider my solution:
Just inherited the std::vector and hide the modifiers such as push_back, emplace_back, erase, then we get a fixed size vector. We can only access and modify the elements with operator [].
template <typename T>
class FixedVector : protected std::vector<T> {
public:
using BaseType = std::vector<T>;
FixedVector(size_t n) : BaseType(n) {}
FixedVector(const T &val, size_t n) : BaseType(val, n) {}
typename BaseType::reference operator[](size_t n) {
return BaseType::operator[](n);
}
};
So in my header file for a class Foo I declare a 2D array of ints like so:
int board[][];
I am intentionally leaving out a size because I want to set that in the constructor. board[][] will not change in size once initialized. One of my constructors looks like this:
Foo(int _board[][]);
In this I want to set board[][] to the same size as _board[][] and to also copy the contents. I have tried using this in the .cpp implementation of Foo:
Foo::Foo(int _board[][]){
board[][] = _board[][]; //Does not work as intended
}
However, this does not work as intended. How can I make board[][] be the same size and have the same contents as _board[][] in the constructor?
C++ is different than Java. int a[][]; is not allowed as variable type. Some misleading C++ feature is that first size is allowed to be left empty:
int foo(int a[]);
int foo(int a[][3]);
int foo(int a[][3][4]);
Another misleading C++ feature is that this is allowed in initialization of an array (compiler will count the size):
int a[][] = {{1,2}, {1,2,3,4}, {1}};
which is equivalent to:
int a[3][4] = {{1,2}, {1,2,3,4}, {1}};
For your very case - use std::vector:
std::vector<std::vector<int>> board;
Foo(std::vector<std::vector<int>> board) : board(board) {}
If you can't use std::vector for whatever reason - then only solution is to use int** with both sizes:
int** board;
size_t s1;
size_t s2;
Foo(int** board = NULL, size_t s1 = 0, size_t s2 = 0) : board(board), s1(s1), s2(s2) {}
But be aware that you cannot use this way:
int board[][] = {{1,1,2},{1,2,2}};
Foo foo((int**)board,2,3);
because you must provide a dynamic array:
int** board = new int*[2] { new int[3]{1,1,2}, new int[3]{1,2,2}};
And since that - you have to implement copy constructor, assignment operator and destructor:
Foo(const Foo& other) : TODO { TODO }
~Foo() { TODO }
Foo& operator = (Foo other) { TODO }
So, just use std::vector.
See the code below - I am trying to put a const object into a vector. I know the answer is "STL containers require objects to be assignable and copy constructable", but, without citing the standard, can anyone explain what the problem with doing this is? I don't understand why a class like this could not be copied (besides that c++ doesn't allow it).
All it is is a value stored that is not allowed to be changed - why can't putting it in a vector simply create another one of these objects?
#include <vector>
// Attempt 1
// /home/doriad/Test/Test.cxx:3:8: error: non-static const member ‘const int MyClass::x’, can’t use default assignment operator
// struct MyClass
// {
// int const x;
// MyClass(int x): x(x) {}
// };
//
// int main()
// {
// std::vector<MyClass> vec;
// vec.push_back(MyClass(3));
// return 0;
// }
// Attempt 2
// /home/doriad/Test/Test.cxx:28:23: error: assignment of read-only member ‘MyClass::x’
struct MyClass
{
int const x;
MyClass(int x): x(x) {}
MyClass& operator= (const MyClass& other)
{
if (this != &other)
{
this->x = other.x;
}
return *this;
}
};
int main()
{
std::vector<MyClass> vec;
vec.push_back(MyClass(3));
return 0;
}
EDIT:
It is possible to do this with std::set and std::list. I guess it is the sort() function in std::vector that uses assignment. This is not UB right?
#include <set>
// Attempt 1
struct MyClass
{
int const x;
MyClass(int x): x(x) {}
bool operator< (const MyClass &other) const;
};
bool MyClass::operator<(const MyClass &other) const
{
if(this->x < other.x)
{
return true;
}
else if (other.x < this->x)
{
return false;
}
}
int main()
{
std::set<MyClass> container;
container.insert(MyClass(3));
return 0;
}
EDIT2: (Removing a bunch of stuff that doesn't have to work) The C++11 standard states that the insert method for vector and deque (and the default implementation of push_back for that matter) requires the value type to be CopyAssignable, i.e., the value supports:
t= v;
Classes and structs with const members are not CopyAssignable by default, so what you want to do won't work.
This doc (n3173) has an explanation for the various container requirements.
One possible solution would be to store pointers to the objects in the vector, because pointers are assignable and copy constructable.
Another possible solution would be to declare x without the const keyword, but ensure that it cannot be modified through encapsulation (i.e. you should declare it as private and don't modify from anywhere outside the constructor)..
When you place an object of type MyClass in the std::vector, the vector will make a copy of the object for storage, and not the object you passed to it.