I'm having a problem which I can't wrap my head around.
I'm writing my own container which is more or less like an std::vector<T> and I don't know how to solve the problem around allocating memory for the objects.
Lets say for instance that I write a wrapper around an array and want to allocate data like this:
T* cArray = new T[size];
cArray[index] = std::move(obj);
If the obj doesn't have a default constructor which doesn't take any parameters Ill get a error: "Class: no appropriate default constructor available".
So I though i could solve the problem by not calling the obj's constructor by using operator new: static_cast<T*>(::operator new(sizeof(T)*this->cap)) and this works only if I use built in types like int, double and floats as members for my Test obj.
If I do something like this:
struct Test
{
Test(int x){}
std::string s;
double d;
}
MyVector<Test> vec;
vec.push_back(Test(1));
I get a runtime error if I try to assign data to the location in my push_back function which contains the following line:
cArray[index] = std::move(obj);
in file: xmemory0 on line 106:
Expression: "(_Ptr_user & (_BIG_ALLOCATION_ALIGNMENT -1)) == 0
Again, this is only a problem when I'm not using built-in types. If I remove the std::string as a member everything works as expected. I have no idea what the cause of the problem might be nor do I know how to solve it after hours of searching.
Do you guys know how to solve this problem?
One answer is to not store T[] but instead store something of the same size and alignment requirements (the choice is most often aligned_storage). Then you use the placement new operator to construct items within it, e.g.
new (&carray[index]) T(...args)
When you are done with items you need to manually call the destructor on each item.
You have the right idea, at least the first half of it. Which is to allocate raw memory, rather than using new Test[N]. But you still need to construct your objects, which you can do using placement new. Given a pointer p which points to a location where you want to construct an object, you can do this:
new (p) Test(...constructor args...);
Also note that when you are done with the object, you will need to call the destructor manually:
p->~Test();
That's the right way to allocate the memory. But you still need to call the constructor eventually, to turn the empty bytes into an object. (And later on you need to call the destructor.)
You'll need to use "placement new" to invoke the constructor:
new (&carray[index]) Test(obj)
Related
I was watching a youtube video on how to implement your own vector/dynamic_array in C++.
I understood everything except one like of code, I'm new to c++ and trying to understand the underline data structure implementation.
But I didn't see such a line of code like that one.
The Code:
template<typename... Args>
T& EmplaceBack(Args&&... args) {
if (m_Size >= m_Capacity) {
ReAlloc(m_Capacity + m_Capacity / 2);
}
new(&m_Data[m_Size])T(std::forward<Args>(args)...);
return m_Data[m_Size++];
}
The line I didn't understand:
new(&m_Data[m_Size])T(std::forward<Args>(args)...);
What that line of code is really doing ?
Btw, I don't really know what std::forward is.
Thx for any explanation. :)
This line of code constructs an object of type T with arguments args... at the address &m_Data[m_Size]. No memory allocation involved.
new(&m_Data[m_Size])T(std::forward<Args>(args)...);
Lets assume we call a "normal" new operator:
new T((std::forward<Args>(args)...);
This will allocate memory which size will be equal to sizeof(T) and call a constructor of type T at that memory address. std::forward is used in the technique called perfect forwarding. In short: no copies, no moves, no passing in any way - arguments are just given to the constructor as if you called it directly.
But what if you have your memory already preallocated - the main performance boosting point of many containers, like the vector? Placement new operator is your friend here. You provide it with the address of the preallocated memory and it only constructs the object. And no delete is required later, because you didn't allocate anything with placement new!
What about the destruction? Normally destructors are called automatically when you delete the object. In this case you'll have to call the object's destructor directly, like this - t->~T();
I'm writing a content management system to avoid duplicates of the same loaded texture in my game engine. The following is the function for retrieving content from the previously loaded in objects or to load in a new object if none is available.
template <class T>
T* GetContent(const char* path) {
// Check if it already exists, if yes return it
for (ContentEntry& entry : m_ContentList) {
// Same Type?
if (strcmp(entry.Type, T::GetType()) == 0)
// Same Path?
if (strcmp(entry.C->GetPath(), path) == 0)
return (T*)entry.C;
}
// Since it doesn't exist, create it
ContentEntry contentEntry (
T::GetType(),
(Content*)new T(path));
// Add it to the list
m_ContentList.push_back(contentEntry);
// And Return it
return (T*)contentEntry.C;
}
And this is the struct used to store content entries and the vector they're stored in.
struct ContentEntry {
const char* Type;
Content* C;
ContentEntry(const char* type, Content* c) :
Type(type),
C(c)
{ }
~ContentEntry() {
delete C;
}
};
std::vector<ContentEntry> m_ContentList;
Whenever this function tries to return the value, the app crashes. When I change contentEntry to a pointer (updating the code around it appropriately) it returns with no problem but I have to change the entire vector to point to ContentEntry pointers and then manually delete them which I would like to avoid if possible. How could I make this function work correctly?
Additionally, when using the pointer and stepping through the foreach loop, the vector seems to grow drastically for no clear reason, how can I stop this from happening?
Edit: For now fixed the crashing problem which I'll later refine, but the vector growing out of control is still there.
Edit2: The vector growing seems to just disappear after exiting the function so I'm just gonna mark something as answer.
From the looks of it, you are deleting something which looks like a string using delete rather than delete[]. Of course, this assumes that the string was allocated in the first place. Based on your comment you try to delete a string literal which causes undefined behavior at that point.
That said, please note that you are slicing your object when you insert it into the vector and, more importantly, you don't get a deep copy of the ContentEntry members (this type is lacking a copy constructor and probably an assignment operator). Thus, after inserting the ContentEntry into your std::vector<ContentEntry> the newly allocated object is gone. Another interesting bit is that you cast your T* to a Content*. The allocate object is deleted through a pointer to Content. Thus, either the cast is unnecessary (and hopefully your type Content has a virtual destructor) or things will start going bad at that point.
// Since it doesn't exist, create it
ContentEntry contentEntry (
T::GetType(),
(Content*)new T(path));
// Add it to the list
m_ContentList.push_back(contentEntry);
// And Return it
return (T*)contentEntry.C;
Your problem is in these three lines, in combination with ContentEntry not having a copy constructor (and copy assignment).
in the first part you create a ContentEntry instance
then you push_back a copy of that instance. this copy will point to the same T instance that the original ContentEntry pointed to.
finally, the function exits, return the pointer-to-T. But at the exit, your local copy contentEntry is destroyed, which will delete the T-instance that the returned pointer points to.
In essence, you are not following the Rule of Three and are being punished for it.
You need a copy constructor for ContentEntry.
I want to ask whether there are some problems with the copy for the vector of pointer items. Do I need to strcpy or memcpy because there may be depth copy problem?
For instance:
Class B;
Class A
{
....
private:
std::vector<B*> bvec;
public:
void setB(std::vector<B*>& value)
{
this->bvec = value;
}
};
void main()
{
....
std::vector<const B*> value; // and already has values
A a;
a.setB(value);
}
This example only assign the value to the class variable bvec inside A class. Do I need to use memcpy since I found that std::vector bvec; has pointer items? I am confused with the depth copy in C++, could you make me clear about that? Thank you.
Think about this, if you remove and delete an item from the vector value after you call setB, then the vector in A will have a pointer that is no longer valid.
So either you need to do a "deep copy", have guarantees that the above scenario will never happen, or use shared smart pointers like std::shared_ptr instead of raw pointers. If you need pointers, I would recommend the last.
There is another alternative, and that is to store the vector in A as a reference to the real vector. However, this has other problems, like the real vector needs to be valid through the lifetime of the object. But here too you can use smart pointers, and allocate the vector dynamically.
It is unlikely you need strcpy or memcpy to solve your problem. However, I'm not sure what your problem is.
I will try to explain copying as it relates to std::vector.
When you assign bvev to value in setB you are making a deep copy. This means all of the elements in the vector are copied from value to bvec. If you have a vector of objects, each object is copied. If you have a vector of pointers, each pointer is copied.
Another option is to simply copy the pointer to the vector if you wish to reference the elements later on. Just be careful to manage the lifetimes properly!
I hope that helps!
You probably want to define your copy constructor for class A to ensure the problem your asking about is handled correctly (though not by using memcpy or strcpy). Always follow the rule of three here. I'm pretty sure with std::vector your good, but if not, then use a for loop instead of memcpy
I have a class Bullet that takes several arguments for its construction. However, I am using a dynamic memory array to store them. I am using C++ so i want to conform to it's standard by using the new operator to allocate the memory. The problem is that the new operator is asking for the constructor arguments when I'm allocating the array, which I don't have at that time. I can accomplish this using malloc to get the right size then fill in form there, but that's not what i want to use :) any ideas?
pBulletArray = (Bullet*) malloc(iBulletArraySize * sizeof(Bullet)); // Works
pBulletArray = new Bullet[iBulletArraySize]; // Requires constructor arguments
Thanks.
You can't.
And if you truly want to conform to C++ standards, you should use std::vector.
FYI, it would probably be even more expensive than what you're trying to achieve. If you could do this, new would call a constructor. But since you'll modify the object later on anyway, the initial construction is useless.
1) std::vector
A std::vector really is the proper C++ way to do this.
std::vector<Bullet> bullets;
bullets.reserve(10); // allocate memory for bullets without constructing any
bullets.push_back(Bullet(10.2,"Bang")); // put a Bullet in the vector.
bullets.emplace_back(10.2,"Bang"); // (C++11 only) construct a Bullet in the vector without copying.
2) new [] operator
It is also possible to do this with new, but you really shouldn't. Manually managing resources with new/delete is an advanced task, similar to template meta-programming in that it's best left to library builders, who'll use these features to build efficient, high level libraries for you. In fact to do this correctly you'll basically be implementing the internals of std::vector.
When you use the new operator to allocate an array, every element in the array is default initialized. Your code could work if you added a default constructor to Bullet:
class Bullet {
public:
Bullet() {} // default constructor
Bullet(double,std::string const &) {}
};
std::unique_ptr<Bullet[]> b = new Bullet[10]; // default construct 10 bullets
Then, when you have the real data for a Bullet you can assign it to one of the elements of the array:
b[3] = Bullet(20.3,"Bang");
Note the use of unique_ptr to ensure that proper clean-up occurs, and that it's exception safe. Doing these things manually is difficult and error prone.
3) operator new
The new operator initializes its objects in addition to allocating space for them. If you want to simply allocate space, you can use operator new.
std::unique_ptr<Bullet,void(*)(Bullet*)> bullets(
static_cast<Bullet*>(::operator new(10 * sizeof(Bullet))),
[](Bullet *b){::operator delete(b);});
(Note that the unique_ptr ensures that the storage will be deallocated but no more. Specifically, if we construct any objects in this storage we have to manually destruct them and do so in an exception safe way.)
bullets now points to storage sufficient for an array of Bullets. You can construct an array in this storage:
new (bullets.get()) Bullet[10];
However the array construction again uses default initialization for each element, which we're trying to avoid.
AFAIK C++ doesn't specify any well defined method of constructing an array without constructing the elements. I imagine this is largely because doing so would be a no-op for most (all?) C++ implementations. So while the following is technically undefined, in practice it's pretty well defined.
bool constructed[10] = {}; // a place to mark which elements are constructed
// construct some elements of the array
for(int i=0;i<10;i+=2) {
try {
// pretend bullets points to the first element of a valid array. Otherwise 'bullets.get()+i' is undefined
new (bullets.get()+i) Bullet(10.2,"Bang");
constructed = true;
} catch(...) {}
}
That will construct elements of the array without using the default constructor. You don't have to construct every element, just the ones you want to use. However when destroying the elements you have to remember to destroy only the elements that were constructed.
// destruct the elements of the array that we constructed before
for(int i=0;i<10;++i) {
if(constructed[i]) {
bullets[i].~Bullet();
}
}
// unique_ptr destructor will take care of deallocating the storage
The above is a pretty simple case. Making non-trivial uses of this method exception safe without wrapping it all up in a class is more difficult. Wrapping it up in a class basically amounts to implementing std::vector.
4) std::vector
So just use std::vector.
It's possible to do what you want -- search for "operator new" if you really want to know how. But it's almost certainly a bad idea. Instead, use std::vector, which will take care of all the annoying details for you. You can use std::vector::reserve to allocate all the memory you'll use ahead of time.
Bullet** pBulletArray = new Bullet*[iBulletArraySize];
Then populate pBulletArray:
for(int i = 0; i < iBulletArraySize; i++)
{
pBulletArray[i] = new Bullet(arg0, arg1);
}
Just don't forget to free the memory using delete afterwards.
The way C++ new normally works is allocating the memory for the class instance and then calling the constructor for that instance. You basically have already allocated the memory for your instances.
You can call only the constructor for the first instance like this:
new((void*)pBulletArray) Bullet(int foo);
Calling the constructor of the second one would look like this (and so on)
new((void*)pBulletArray+1) Bullet(int bar);
if the Bullet constructor takes an int.
If what you're really after here is just fast allocation/deallocation, then you should look into "memory pools." I'd recommend using boost's implementation, rather than trying to roll your own. In particular, you would probably want to use an "object_pool".
I'm not a very experienced c++ coder and this has me stumped. I am passing a object (created elsewhere) to a function, I want to be able to store that object in some array and then run through the array to call a function on that object. Here is some pseudo code:
void AddObject(T& object) {
object.action(); // this works
T* objectList = NULL;
// T gets allocated (not shown here) ...
T[0] = object;
T[0].action(); // this doesn't work
}
I know the object is passing correctly, because the first call to object.action() does what it should. But when I store object in the array, then try to invoke action() it causes a big crash.
Likely my problem is that I simply tinkered with the .'s and *'s until it compiled, T[0].action() compliles but crashes at runtime.
The simplest answer to your question is that you must declare your container correctly and you must define an appropriate assigment operator for your class. Working as closely as possible from your example:
typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
arrayFromElsewhere[0].action();
}
Note the signature change to const reference which emphasizes that we are going to copy the original object and not change it in any way.
Also note carefully that arrayFromElsewhere[0].action() is NOT the same as objInstance.action() because you have made a copy — action() is being invoked in a different context, no matter how similar.
While it is obvious you have condensed, the condensation makes the reason for doing this much less obvious — specifying, for instance, that you want to maintain an array of callback objects would make a better case for “needing” this capability. It is also a poor choice to use “T” like you did because this tends to imply template usage to most experienced C++ programmers.
The thing that is most likely causing your “unexplained” crash is that assignment operator; if you don't define one the compiler will automatically generate one that works as a bitwise copy — almost certainly not what you want if your class is anything other than a collection of simple data types (POD).
For this to work properly on a class of any complexity you will likely need to define a deep copy or use reference counting; in C++ it is almost always a poor choice to let the compiler create any of ctor, dtor, or assignment for you.
And, of course, it would be a good idea to use standard containers rather than the simple array mechanism you implied by your example. In that case you should probably also define a default ctor, a virtual dtor, and a copy ctor because of the assumptions made by containers and algorithms.
If, in fact, you do not want to create a copy of your object but want, instead, to invoke action() on the original object but from within an array, then you will need an array of pointers instead. Again working closely to your original example:
typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
arrayFromElsewhere[0]->action();
}
Note closely that arrayFromElsewhere is now an array of pointers to objects instead of an array of actual objects.
Note that I dropped the const modifier in this case because I don’t know if action() is a const method — with a name like that I am assuming not…
Note carefully the ampersand (address-of) operator being used in the assignment.
Note also the new syntax for invoking the action() method by using the pointer-to operator.
Finally be advised that using standard containers of pointers is fraught with memory-leak peril, but typically not nearly as dangerous as using naked arrays :-/
I'm surprised it compiles. You declare an array, objectList of 8 pointers to T. Then you assign T[0] = object;. That's not what you want, what you want is one of
T objectList[8];
objectList[0] = object;
objectList[0].action();
or
T *objectList[8];
objectList[0] = &object;
objectList[0]->action();
Now I'm waiting for a C++ expert to explain why your code compiled, I'm really curious.
You can put the object either into a dynamic or a static array:
#include <vector> // dynamic
#include <array> // static
void AddObject(T const & t)
{
std::array<T, 12> arr;
std::vector<T> v;
arr[0] = t;
v.push_back(t);
arr[0].action();
v[0].action();
}
This doesn't really make a lot of sense, though; you would usually have defined your array somewhere else, outside the function.