I'm not very experienced with C++ yet, so bear with me if this is basic stuff.
I have some code like that below. L is an abstract class (it has a number of pure virtual functions), and A, B and C are regular classes all derived from L. There may be any number of these, and they are all different.
int main() {
// ...
std::vector<L*> ls(3) ;
ls[0] = new A ;
ls[1] = new B ;
ls[2] = new C ;
int i ;
for (i = 0 ; i < ls.size() ; i++) {
if (ls[i]->h()) {
// ...
}
}
// ...
}
It works, but there really has to be a better way to initialise that vector. Right?
The vector is not supposed to change after it has been first initialised. I figure I can't make it const, however, because the various objects may themselves change internally. I picked a vector over a regular array because I don't want to manually keep track of its length (that proved error prone).
Ideally I'd like to pull the definition and initialisation of the vector out of main and preferably into a separate file that I can then #include. When I try that the compiler complains that it "expected constructor, destructor, or type conversion before ‘=’ token". All the classes A, B and C have default constructors.
Also, I was under the impression that I have to manually delete anything created using new, but it won't delete ls with either delete or delete[]. If I try delete ls; the compiler complains that "type ‘class std::vector<L*, std::allocator<L*> >’ argument given to ‘delete’, expected pointer".
Is the above even safe or does it cause some memory problems?
but there really has to be a better way to initialise that vector. Right?
I don't think so, at least not without C++0x. Which way would you prefer? Your initialization code is completely fine.
I figure I can't make it const, however, because the various objects may themselves change internally.
You can still make the vector itself const, only its member type cannot be a pointer to const then.
I picked a vector over a regular array because I don't want to manually keep track of its length (that proved error prone).
You don't have to keep track of the length in constant arrays:
L* ls[] = { new A, new B, new C };
// with <boost/range/size.hpp>
std::size_t num = boost::size(ls);
// without Boost, more error-prone
// std::size_t num = sizeof ls / sizeof ls[0];
And often you don't need the size anyway, e.g. with Boost.Range.
Ideally I'd like to pull the definition and initialisation of the vector out of main and preferably into a separate file that I can then #include.
That would violate the one-definition rule. You can put the declaration into a header file, but the definition has to go into a source file.
Also, I was under the impression that I have to manually delete anything created using new, but it won't delete ls with either delete or delete[].
Your impression is correct, but you haven't created ls with new, only its elements. After using the vectors, you have to delete each of its elements, but not the vector itself.
The recommended alternative to STL containers holding polymorphic pointers is the Boost pointer container library.
You do indeed have to use delete on the objects you created. You are calling delete on the vector not the objects. Something like:
for(size_t i = 0; i < ls.size(); i++){
delete ls[i];
}
For your construction issue you could wrap them into a function and put that function in it's own header file. You would have to make sure to include all of the relevant classes header files as well.
void init_vector(std::vector<LS*> & v){
ls[0] = new A ;
ls[1] = new B ;
ls[2] = new C ;
}
If C++11 is acceptable, you might be better off with an std::array instead of std::vector:
std::array<L *, 3> = {new A(), new B(), new C()};
Since you know the size at compile time, I suggest using an array instead of a vector. Using the class template array instead of a C-style array gives you the benefit of a standard container interface, just like a vector. That is, you can call size() on the array and obtain iterators and so on.
And to make sure you don't forget to delete the objects, I suggest using smart pointers:
#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
boost::array<boost::shared_ptr<L>, 3> ls = { {
boost::make_shared<A>(),
boost::make_shared<B>(),
boost::make_shared<C>(),
} };
Modern compilers ship their own versions of array and shared_ptr in the standard library:
#include <array>
#include <memory>
std::array<std::shared_ptr<L>, 3> ls = { {
std::make_shared<A>(),
std::make_shared<B>(),
std::make_shared<C>(),
} };
Note that the outermost braces are technically not needed, but leaving them out might produce compiler warnings, at least that's what happens on my compiler.
Ideally I'd like to pull the definition and initialization of the vector out of main and preferably into a separate file that I can then #include
In that case, you need a header file with a declaration and an implementation file with a definition of ls:
// file ls.h
#ifndef LS_H
#define LS_H
#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
extern boost::array<boost::shared_ptr<L>, 3> ls;
#endif
// file ls.cpp
#include "ls.h"
#include <boost/make_shared.hpp>
boost::array<boost::shared_ptr<L>, 3> ls = { {
boost::make_shared<A>(),
boost::make_shared<B>(),
boost::make_shared<C>(),
} };
Related
Good whatever part of the day you're reading this!
I've been trying to implement my own version of an std::deque-like container. I thought it would be possible to use templates to customise the size and type of the inner array 'blocks', but I can't seem to get the syntax right. Or at least I think what I'm doing is somehow possible.
template<typename T, int ChunkSize>
class ChunkList
{
public:
ChunkList()
{
T first[ChunkSize] = new T[ChunkSize];
// error: array must be initialized with a brace-enclosed initializer
m_ChunkPointers.push_back(first);
}
private:
// store pointers to the chunks
std::vector<T[]> m_ChunkPointers;
};
int main()
{
ChunkList<int, 4> cl = new ChunkList<int, 4>();
}
// compiled with g++ on a windows x64 machine
I found a Stack Overflow answer relating to the brace-enclosed initializer but I don't know how to initialize those with the template syntax.
The only other solution I can think is is using something like malloc(sizeof(T) * ChunkSize) and then casting that to an T[] or something.
Either way any help/advice would be greatly appreciated, always happy to learn new things!
PS: Even if there is a way more efficient solution I'd still like to know if there is a way to make templates behave the way I intend to here, or rather why this isn't valid.
You are already using std::vector why not a proper container for the chunks too?!?
template<typename T, int ChunkSize>
struct ChunkList {
ChunkList() : m_Chunks(1) {}
private:
std::vector<std::array<T,ChunkSize>> m_Chunks;
};
// store pointers to the chunks - You do not want to store pointers, you want to store arrays. You attempted to store them on the heap, but that complication is totally unnecessary, because they are of fixed size and std::vector does already manage its elements in dynamically allocated memory.
We have a few problems here.
1: In main you wrote ChunkList<int, 4> cl = new ChunkList<int, 4>();
This will not work because new will return a ChunkList* not a ChunkList you need to write ChunkList<int, 4>* cl = new ChunkList<int, 4>(); or ChunkList<int, 4> cl{}; depending on the hact if you need an object or a pointer to an object
2:std::vector<T[]> m_ChunkPointers; declares a vector of empty arrays. I think you menat to write std::vector<T*> m_ChunkPointers; storeing pointers (to the start of the arrays.)
3: T first[ChunkSize] = new T[ChunkSize]; needs to be T *first = new T[ChunkSize];
You mixed together the T x[N]; sintax and the T*x=new T[N]; syntax. the first will create an array on the stack the second will create one array, living until the end of the function on the heap, living until you detete it.
Note: Welcome to C++. In C++ the variables the object themself, not referances/pointers. You need to manage the lifetimes of the objects living in the heep. If you don't want to delete every object you used I suggest to take a look on unique_ptr and shared_ptr
Basically I am trying to make an array which will get larger every time the user enters a value. Which means I never know how long the array will be. I don't know if this is something to do with my class or anything.
#pragma once
#include <iostream>
#include <string>
#define dexport __declspec(dllexport)
//Im making an DLL
using namespace std;
class dexport API {
private:
string users[] = {"CatMan","ManCat"}; //Line With Error Incomplete Type Is Not Allowed
public:
string getAllUsers(string list[]) {
for (unsigned int a = 0; a < sizeof(list) / sizeof(list[0]); a = a + 1) {
return list[a];
}
}
};
It gives me an error Incomplete type is not allowed. I really have no idea what to do.
Compiler Error
There are a few things wrong with your code. For starters, an array has a fixed size, so, even if your code did compile, it wouldn't work. Normally, the compiler would infer the size of your array from the length of the initializer; but you are creating a class, and it needs to know it, hence the error.
This will solve your compilation problem:
string users[2] = {"CatMan","ManCat"};
But then your array has a fixed size, and that is not what you want, so you need an std::vector:
#include <vector>
[...]
vector<string>users = {"CatMan","ManCat"};
Now you can use the '[]' operator to access the strings, and users.push_back to add new users.
The next problem you need to solve is the way you are trying to return your value: you shouldn't use an argument as an out value (although you can, with either a reference or a pointer). You should decide whether you want to return a reference to your vector, a copy of your vector, or a const reference, for example:
// Returning a copy
vector<string> getAllUsers() {
return users;
}
// Returning a reference
vector<string>& getAllUsers() {
return users;
}
Finally, you are creating a library: you should know that if you want to share memory between different processes, you need to use some kind of shared memory. Currently, every program will keep its own copy of the API.
What you are looking for is an std::vector.
You can find more info here.
It's somewhat similar to an array, except that it allows variable length.
You can use std::vector. It allocate and copy elements to new place if it got out space.
If you wanna make the class yourself for educational reason here is what you should try as a basic solution:
You allocate some memory up front and store its length as capacity. You need a variable(size) to store the number of elements already entered to the class e.g. via a push_back function. Once the size reached capacity, you need to reallocate memory copy over all the elements and then delete the old memory.
I have a class like:
class CPR_data{
public:
/*some functions*/
private:
map<int,double*> data; //saving data
};
In the file main.cpp, I add data into the class as following:
double *data_ = new double[n_var];
auto insert_flag = data.insert(make_pair(n,data_));
I used the default destructor but it seems a Memory Leak. Do I need to delete all the arrays manually in the destructor?
You loop through your map and call delete[] on every element.
~CPR_data()
{
for(auto& elem : data)
{
delete[] elem.second;
}
}
Note that you now also have to write your own copy constructor and copy assignment operator.
However, the real solution is to use std::map<int, std::vector<double>> instead so you won't have to do any bookkeeping and any questioning about who owns what pointer etc. There's a good chance it'll be as fast as your dynamic allocation method.
You really shouldn't be using any dynamic allocation in C++11 since everything nowadays has a better alternative unless you're writing a standard library implementation or some other exotic piece of code.
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int main()
{
map<int, vector<double>> data;
vector<double> data_ = { 1.0, 2.0, 3.0, 4.0, 5.0 };
auto insert_flag = data.insert(make_pair(1, data_));
vector<double> data_2 = { 1.1, 2.2, 3.3, 4.4 };
insert_flag = data.insert(make_pair(2, data_2));
for(const auto& val : data[2])
cout << val << '\n';
return 0;
}
You don't need to implement your own destructor just for that case. The only thing you have to ensure is to make the double* get deleted when your object is destroyed.
Implementing a destructor that will run through all items is one option, but you can also (as others said) switch to using some other element type. vector is one option, but surely that's not an array.
If you need to stick with raw dynamic arrays, you can always wrap the raw pointer into a smart pointer that will keep track of it and will delete it appropriately.
#include <iostream>
#include <map>
#include <boost/scoped_array.hpp>
int main()
{
std::map<int,boost::scoped_array<double>> data;
int n = 250;
double* data_ = new double[n]; // POTENTIAL LEAK
data_[249] = -1; // POTENTIAL LEAK
/* ... */ // POTENTIAL LEAK
auto insert_flag = data.insert(std::make_pair(n,data_));
std::cout << insert_flag.first->first << " " << insert_flag.second << std::endl;
std::cout << data[250][249] << std::endl;
}
Please be careful with smart pointer type - here I'm using scoped_array as opposed to typical scoped_ptr which is appropriate only for pointers to single object. For dynamic arrays, scoped_array is needed.
Nevertheless, as you can see above, using smart pointer is very similar to using raw pointer. Smart pointers were designed to be as much similar in use as possible. They come with their own destructors, so when the (default) destructor of your object kicks in, it destroys the map, which in turn destroys its elements - and now the elements are smart-pointer - so they will deallocate the arrays.
Actually, I still would encourage you to use vector or whatever else than raw pointers. With raw dynamic allocations you have to be extra careful because even in my example above, there is a tiny possibility of a memory leak - if anything interrupts the code (i.e. exception) between new'ing the raw pointer and packing the pointer into scoped one - nothing will deallocate the raw dynamic array. For that reason, it's best to wrap them as soon as possible and ensure, as hard as it can be, that nothing can interrupt the flow before the raw pointer starts being managed by smart pointer object.
And, as last line - be sure to check out the difference between scoped and shared smart pointers. I used scoped here, because it seems fit. However, it's worth knowing about both types.
How to write the following code using new operator?
Please explain in detail.
Thanks in advance.
#include<alloc>
#define MAXROW 3
#define MAXCOL 5
using namespace std;
int main()
{
int (*p)[MAXCOL];
p = (int(*)[MAXCOL])malloc(MAXROW*sizeof(*p));
}
Quite simply, to answer the question literally:
p = new int[MAXROW][MAXCOL];
This allocates a 2D array (MAXROW by MAXCOL) on the free store and, as usual with new, returns a int(*)[MAXCOL] - the same type as decaying the 2D array. Don't forget to delete[] p;.
The last part brings up the importance of std::vector. Presumably, you know the size of the second dimension at compile-time. Therefore, a std::vector<std::array<int, MAXCOL>> would work with the added bonus of not requiring a delete[] statement, plus it knows its size (MAXROW). Please use this if at all possible.
In fact, in your example, both dimensions are known at compile-time, meaning a std::array<std::array<int, MAXCOL>, MAXROW> would also work here. That's typically preferable to dynamic allocation.
If neither dimension is known at compile-time, your best bet is usually a vector of vectors or a dedicated matrix class to increase performance when you know every inner vector is the same size.
Since this is C++ I will recomend using std::array and std::unique_ptr
Also when using malloc you should use free un-alloc or free the memory, if you use new you need to use delete; if you new[] you need to use delete[]
#include <cstdlib>
#include <memory>
#include <array>
#define MAXROW 3
#define MAXCOL 5
using namespace std;
int main()
{
int (*p)[MAXCOL];
p = (int(*)[MAXCOL])malloc(MAXROW*sizeof(*p));
free(p); //free memory
array<int,MAXCOL> *p1 = new array<int,MAXCOL>[MAXROW];
delete []p1; //use this to delete the variable
array<array<int,MAXCOL>,MAXROW> *p2 = new array<array<int,MAXCOL>,MAXROW>;
delete p2; // normal delete for this one
auto p3 = make_unique<array<array<int,MAXCOL>,MAXROW>>();
//no delete needed for p3, it is a smart pointer.
}
The literal question
” How to write the following code using new operator?
… means something else than you think it means.
The new operator is a simple allocation function roughly directly analogous to C's malloc, except the C++ new operator is replacable by a user defined one.
You probably mean a new expression. Such an expression invokes the new operator for allocation, and then invokes a constructor for initialization, if the allocated thing is of class type. And it's type safe.
Still, for your array you'd not want that either, but simply std::vector from the standard library.
Here's an example using a std::vector of vectors to create a matrix:
#include <vector>
using namespace std;
auto main()
-> int
{
int const n_rows = 3;
int const n_cols = 5;
using Row = vector<int>;
vector<Row> v( n_rows, Row( n_cols ) );
// E.g. v[1] is a row, and v[1][2] is an int item in that row.
}
Even if you don't so often use matrices, it can be a good idea to wrap the general notion of a matrix, in a class. A simple way is to use a single std::vector for storage, and provide e.g. an at function or an operator() for indexing from client code. If you don't yet feel like doing this yourself, then e.g. the Boost library provides a matrix class.
Take a variable length struct (if this were a real program, an int array would be better):
#include <vector>
struct list_of_numbers(){
int length;
int *numbers; //length elements.
};
typedef std::vector<list_of_numbers> list_nums; //just a writing shortcut
(...)
And build a vector out of it:
list_nums lst(10); //make 10 lists.
lst[0].length = 7; //make the first one 7 long.
lst[0].X = new int[7]; //allocate it with new[]
(...)
The above works for g++ in ubuntu. The new() calls are needed to avoid segfaults. Can the lst vector be deleted all at once when it is no longer needed, or will the new calls cause a memory leak? It would be tedious to manually delete() all of the parts called with new().
The typical ways to do this in C++ would be to define constructors and destructors and assignment operators for the list_of_numbers struct that take care of the memory management, or (much better) use a std::vector<int> for the numbers field and get rid of the length field.
But if you do that, you may as well get rid of the struct entirely, and just do this:
#include <vector>
typedef std::vector<int> list_ints;
typedef std::vector<int_ints> list_lists;
(...)
list_lists lst(10); // make 10 lists.
lst[0].resize(7); // set length of the zeroth list to 7
Why not just use a vector of vector of int? That's it's job. You should not be calling new outside of a dedicated class.
In general, you would want to put cleanup code in the destructor of the object (~list_of_numbers()) and memory creating code in the constructor (list_of_numbers()). That way these things are handled for you when the destructor is called (or when the object is created).