I need to create a simple template container, which can store any object of any type and could be used everywhere. So, I did something like this:
template <typename Type>
class Container {
public:
Container() : arraySize(10) { valueWrappers = new Type[arraySize];}
Container(const Container& other) { /* --- */}
~Container() { /* --- */}
Container& operator=(const Container& other) { /* --- */}
/* some functions */
private:
int arraySize;
Type* valueWrappers;
};
Now I have the problem - when I'm trying to create my container using as template a class without default constructor, the compilation error appears:
class MyClass {
public:
MyClass(int value) :v(value) { }
private:
int v;
};
int main() {
Container<MyClass> cont;
return 0;
}
C2512 'MyClass': no appropriate default constructor available
The problem is that I need to initialize the array of "Type" values with something, but I don't no what I need to use. I can't use NULL because, in this case, Container will work only with pointers. So, can somebody give an advice, how am I able to do it? Or, maybe, there is another way to solve this task?
Based on your requirements, I think you're going to have to use placement new. Since you haven't provided all the relevant code, I'm going to do what I can.
First, you're going to have to allocate raw memory instead of using new directly.
Container() : arraySize(10) { valueWrappers = reinterpret_cast<Type*>(::operator new(sizeof(Type) * arraySize)); }
Now when you put something in your Container, you'll have to construct it in place, using something like the following:
new (valueWrappers + index) Type(arguments to type);
In your destructor, you'll need to explicitly call the destructors on any object that you used placement new for.
valueWrappers[index]->~Type();
Lastly, release the memory using ::operator delete.
::operator delete(valueWrappers);
Please bear in mind that this is a very quick and dirty answer, and this code can be hard to debug and maintain. You're going to have to keep track of what indexes in valueWrapper have been initialized and which haven't during cleanup. If possible, I highly recommend using something akin to std::vector, which handles all this complexity for you.
One option is to not allocate the array in the default constructor, but initialise valueWrappers to null instead. Another option is to not have a default constructor in your template. Third option is to keep your class as-is and simply document that the template is default constructible only if the type argument is default constructible.
You can use std::optional to defer initialization, which is guaranteed to handle object lifetime correctly. Letting a default constructed container have 10 elements is also a questionable choice — a (count) constructor may be preferable.
template <typename Type>
class Container {
using elem_t = std::optional<Type>;
std::size_t count{};
std::unique_ptr<elem_t[]> elems{};
public:
Container() = default;
Container(std::size_t cnt)
: count{cnt}
, elems{std::make_unique<elem_t[]>(cnt)}
{
}
// for example
template <typename... Args>
void construct_at(std::size_t pos, Args&&... args)
{
assert(pos < count);
assert(!elems[pos]);
elems[pos].emplace(std::forward<Args>(args)...);
}
// ...
};
Note that I used std::unique_ptr to simplify memory management; a pointer will also be OK, though apparently more error-prone. Now you can traverse the container and construct the elements:
class MyClass {
public:
MyClass(int value) :v(value) { }
private:
int v;
};
int main()
{
Container<MyClass> cont(10);
for (std::size_t i = 0; i < 10; ++i) {
cont.construct_at(i, /* argument */);
}
}
Related
I have a std:array something like this:
class MyClass {
private:
std::array<MyComplexType, 10> myArray;
}
In the constructor, I need to do the following:
MyClass::MyClass() : myArray({
MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)),
... repeated 8 more times...
MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4))
})
Now, I want the 10 to be a compile-time constant that I can modify without having to copy&paste more (or less) of those initializers. They are all the same, I just need a "repeat n times". Everything up to and including C++17 is fair game.
I am 99.9% certain this should be doable with some template magic, but so far I came up with nothing that worked. Any ideas?
(And if it is impossible with templates, maybe with macros? Though I would hate having to go that direction...)
If you want to use a std::array you are going to need to build a helper function, namely a delegating constructor. Your default constructor will then call the delegate to actually initialize the member. That can look like
class MyClass {
public:
// default c'tor, create sequence of 10 integers
MyClass() : MyClass(std::make_index_sequence<10>{})
private:
// delegate, take a sequence and expand the initializer of myArray sizeof...(Is) times
template <std::size_t... Is>
MyClass(std::index_sequence<Is...>) :
myArray{ (Is, MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)))... } {}
std::array<MyComplexType, 10> myArray;
}
You can instead change myArray to be a vector instead and that would let you simplify the code to
class MyClass {
public:
MyClass() :
myData(MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)), 10) {}
private:
std::vector<MyComplexType> myData;
}
You could wrap the type into another struct/class which would provide an appropriate default constructor:
int f(int n)
{
return n;
}
struct S
{
S(int n) : n(n) { }
int n;
};
class MyClass
{
struct Wrapper
{
S s;
Wrapper() : s(f(7)) {}
};
std::array<Wrapper, 10> myArray;
};
You're now delegating the initialisation to the wrapper.
You might yet invest some work makeing the need of explicit indirection (myArray[i].s) obsolete, e.g. wrapping the array itself into another struct/class, too, providing the same interface as a std::array (as far as you need at least…) but with its iterators and index operators dereferencing to the complex type instead of to the wrapper (i.e. your iterator wraps around an array's iterator with S& operator*() { return i->s; } S* operator->() { return &i->s; } and further operators like increment just delegating to the wrapped iterator).
I would like to implement a simple template ObjectPool kind of class.
It has a fixed size vector as a member variable, which elements' are default initialized upon creation.
That's done already and works fine.
The question is what is the best way to assign new elements to the member vector?
I implemented add_old_way member function, which is able to add any type of data to the ObjectPool, and works fine.
My only problem is that i create an extra object which i pass to that function, and inside, i just throw it away after assignment. Waste of resources, if we are talking about giant classes.
How should i implement add_new_way function which is able to take arbitrary parameters and assign them individually to vector element?
Please note ObjectPool is templated so any kind of class can be it's type, not just Bar or Matrix2x2 as in the example below.
I don't eve now the key words here to look it up on the internet, neither if it's possible at all.
Thank you!
template <class T>
class ObjectPool
{
vector<T> mObjects;
ObjectPool() : mObjects(size)
{
}
//that's what i could come up with to add an object to the object pool
void add_old_way(const T& object)
{
...
mObjects[nextFreeIndex] = object;
...
}
//desired way of adding object
void add_new_way(...)
{
mObjects[nextFreeIndex].param1 = param1;
mObjects[nextFreeIndex].param2 = param2;
...
mObjects[nextFreeIndex].paramN = paramN;
}
};
class Bar
{
Bar(int x, string s)
{
mX = x;
mS = s;
}
int mX;
string mS;
};
int main()
{
ObjectPool<Bar> v;
ObjectPool<Matrix2x2> v;
//that's what i could come up with
v.add_old_way(cBar(1,"asdf"));
v.add_old_way(cMatrix2x2(1,2,3,4));
//desired way of adding object
v.add_new_way(1,"asdf");
v.add_new_way(1,2,3,4);
}
Utilize move semantics and perfect forwarding to make the assignment cheap:
template <typename... Args>
void add_new_way(Args&&... args)
{
mObjects[nextFreeIndex] = T{std::forward<Args>(args)...};
}
Live on Coliru
Since the object being assigned from is a temporary, the move-assignment operator of the object being assigned to will be invoked if it exists. This will let the object transfer ownership of any expensive-to-copy resources from the temporary to the object in the pool.
For further reading, take a look at this question: What are move semantics?
If using C++11 and above, to implement your add_new_way method, you can use variadic template parameters and forwarding:
template <typename... Args>
void add_new_way(Args... args) {
mObjects.emplace_back(std::forward<Args>(args)...);
}
Then calling code can do:
v.add_new_way(arg1, arg2, ..., argN);
A library which I can't modify has a type akin to the following:
class A {
public:
A () : A(0) { }
explicit A (int const value) : value_(value) { }
A (A const &) = delete;
A (A &&) = delete;
A & operator= (A const &) = delete;
A & operator= (A &&) = delete;
private:
int value_;
}
Now, I have a class which requires a bunch of As as members. Due to other restrictions of the environment I'm working in all of these As must either be separate members or a member array (i.e. I can't use an std::vector to put them in or create pointers to them). I.e. my class boils down to this:
struct Foo {
A a[2];
}
Is there any way to initialize each member with a distinct initial value? I've been trying various forms of using braced-list initialization, but they all fail due to either A(int) being explicit or A not having a copy/move-constructor.
What doesn't work:
Foo () : A{ { 1 }, { 2 } } { }: won't call A(int) since it's explicit.
Foo () : A{ { A(1) }, { A(2) } } { }: can't copy- nor move-assign.
Edit: Updated info about member array requirement.
Edit 2: The library in question is SystemC. My example class A is a port (e.g. sc_core::sc_in).
The reason I can't use an array of pointers is because, as far as I know, Mentor Graphic's Questa can't really deal with them. It will simulate the model correctly, but won't allow inspection of the ports. I.e. it won't be able to plot the port's values over time in a wave window. I would be very happen to be proven wrong about this, because that would allow a trivial solution to my problem.
Edit 3: Apparently this is a big issue anymore in a newer version of Questa. I'm not sure what changed between seeing this problem and now, could be a change to the development environment as well (which is also out of my control). In any case, my Questa now automatically names ports after their variable name (unless explicitly renamed at construction), so all is well.
Just for the sake knowing how to I'd still like to see potential solutions to the original problem though.
struct Foo {
A a[2];
}
Is there any way to initialize each member with a distinct initial
value? I've been trying various forms of using braced-list
initialization, but they all fail due to either A(int) being
explicit or A not having a copy/move-constructor.
You may need to use placement-new to create an array of A in some raw storage array. You then create a std::initializer_list<ARGUMENT> of the ARGUMENTs needed to construct each A. Something like:
template<typename T, std::size_t Size, std::size_t Alignment = alignof(T)>
struct FixedArray{
std::aligned_storage_t<sizeof(T), Alignment> data[Size];
static constexpr std::size_t size = Size;
template<typename U>
FixedArray(std::initializer_list<U> ls){
assert(ls.size() <= Size && "Invalid Size"); int index = 0;
for(auto& x : ls)
new (&data[index++]) T(x);
}
FixedArray(const FixedArray&) = delete;
FixedArray(FixedArray&&) = delete;
A& operator[](std::size_t index){
auto ptr = reinterpret_cast<A*>(&data) + index;
return *std::launder(ptr); //Sort of a legal way to alias memory C++17
}
~FixedArray(){
for(std::size_t i = 0; i < size; i++)
this->operator[](i).~T();
}
};
Then declare Foo:
struct Foo {
FixedArray<A, 4> a;
};
To create Foo having A(546), A(99), A(-4), A(0):
int main() {
Foo f{{546, 99, -4, 0}};
return 0;
}
See a working Demo
After testing with GCC 6.3 at -O3 optimization levels, about exactly the same assembly is generated for using FixedArray vs plain raw arrays, See it on gcc.godbolt.com.
I am able to solve the problem as follows (also using SystemC, here my non-copyable, non-movable items are sc_modules):
class Object : sc_module {
Object(sc_module_name name){}
};
class Container : sc_module {
std::array<Object, 3> objects;
Container(sc_module_name name) :
objects{{{"object1"},{"object2"},{"object3"}}}
{}
};
The short answer - no. The longer answer - kind of, but its disgusting.
Take a look at this discussion.
I have to write a generic data structure that resembles a C++ vector as part of an assignment.
This is my idea for the Vector:
template<typename T>
class MyVector {
private:
T* data_;
size_t size_;
public:
MyVector();
MyVector(const MyVector &otherVector);
// which one should I use?
add(const T& value);
add(T value);
~MyVector();
};
Now I wonder how to pass values to the methods. Coming from Java I am a bit overwhelmed. In Java you wouldn't hesitate and pass the value by reference, the GC would never delete the object if it is still referenced.
In C++ you would create a mess if you would pass by reference considering code like this:
void myFunction(MyVector &myVector) {
int a = 5;
myVector.add(a);
}
int main() {
auto vector = MyVector<int>();
myFunction(vector);
// now the vector contains a reference to
// something that doesn't exist anymore.
}
How do you solve this problem? Would you just pass by reference and create a copy or do you pass by value (which creates a copy for you)
Looking at the C++ std::vector interface I see that they use references.
I just don't see the value of passing by reference if you have to create your own copy.
add(const T& value) is ok, you just should be sure that there is properly defined assign operator for T. So, the implementation will be:
void Add(const T& value) {
if (m_size == m_maxSize) realloc(); // stuff to have enough space
m_data[m_size++] = value; // here copy is creating
}
default impl of assign operator just byte-copy fields of class, it is not always correct.
Other solution, if you want more java-style semantic, is to make T = shared_ptr<YourType> or T = YourType*
The latter is rather difficult because require skill of manual lifetime control, so is undesirable for c++ beginners.
void myFunction(MyVector<shared_ptr<X>> & myVector)
{
shared_ptr<X> x(new X(...));
myVector.add(x);
}
works similar to references in Java.
Other way, that was used in old times:
template<typename T>
class MyVector {
private:
T** data_; // now you have array of pointers, so should be careful
....
add(T* value);
....
}
void myFunction(MyVector<X> & myVector)
{
X * x = new X(...);
myVector.add(x); // now x belongs to myVector and it should handle its lifetime
}
I build a class for containing vectors with no default constructor. Specifically:
template<typename T>
struct MyVector
{
public:
int GetN(void)
{
return n;
}
MyVector(int n1)
{
n=n1;
ListElt = new T[n1];
}
~MyVector()
{
delete [] ListElt;
}
// some other irrelevant to the question code
private:
int n;
T *ListElt;
};
Now I want to build a class derived from it that contains one integer and a vector.
The code that works is the following:
struct EquivInfo {
public:
EquivInfo(int inpOrbit, MyVector<int> &inpMat)
{
iOrbit=inpOrbit;
eVect=new MyVector<int>(inpMat.getN());
// some code for copying the vector in place.
}
~EquivInfo()
{
delete eVect;
}
private:
int iOrbit;
MyVector<int> *eVect;
};
Is there a way to avoid the use of the pointer for the vector?
The problem is that if I remove the pointer then there is a call to a constructor of the kind MyVector(). I do not understand why. There should be a way to have a constructor for EquivInfo that calls a precise constructor for MyVector
I could add a constructor MyVector(), i.e. a default constructor that set the vector to something trivial. But precisely, I want to avoid such kind of constructors so that all vectors are well defined and the code is clean. The use of the pointer allows me to have a reasonable situation but I wonder if there is a clean way to avoid it.
Use member initializer list:
class EquivInfo {
public:
EquivInfo(int inpOrbit, MyVector<int> &inpMat)
: eVect(inpMat.getN())
, iOrbit(inpOrbit) {
// some code for copying the vector in place.
}
// ....
MyVector<int> eVect;
}