Is there any way to dynamically (I think that's the right term) define an int array in a class, the size of which is a private member variable in that same class? For example:
class Scene()
{
//public member functions
private:
int max;
int xcoords[max];
}
I've searched through other answered questions on here, but I haven't learned how to use vectors in class yet, which is what most responses suggest. Ideally, in my constructor for the class, I'd be passed an int max, with which I then initialize the xcoord array to have a size of max with entries all -1.
If you want dynamic sizing for your member data, you almost certainly have to store it in the heap. Which means, something like this
class Foo{
int* data;
public:
Foo(int size){
data = new int[size];
}
~Foo(){
// remember to clean up
delete[] data;
}
}
This way, your constructor will allocate size for size ints in the heap memory when the class is created, and free it up when it is deleted.
The more official c++ way of writing the constructor is:
Foo(int size):
data(new int[size])
{
}
But in the end it will do the same thing.
Consider leaving memory management to standard libraries.
Instead of Arrays, use vectors.
#include <vector>
#include <iostream>
using std::vector;
using std::cout;
using std::endl;
class Scene
{
public:
vector<int> verticeData;
};
int LEGACY_FUNCTION(const int * data, int count)
{
for (int i = 0; i < count; ++i)
{
cout << " ";
cout << data[i];
cout << " ";
}
cout << endl;
return 0;
}
int main()
{
Scene myscene;
myscene.verticeData.emplace_back(3);
myscene.verticeData.emplace_back(4);
myscene.verticeData.emplace_back(5);
LEGACY_FUNCTION(myscene.verticeData.data(), myscene.verticeData.size());
myscene.verticeData.clear();
myscene.verticeData.emplace_back(1);
myscene.verticeData.emplace_back(7);
LEGACY_FUNCTION(myscene.verticeData.data(), myscene.verticeData.size());
return 0;
}
Related
Here is a simple code:
#include <iostream>
#include <string>
typedef struct Car{
std::string model;
} Car;
std::string get_model() {
std::string str = "Maserati";
return str;
}
int main() {
const int nCars = 2;
//Car *list = new Car[nCars]; // works everywhere g++/VC++
Car *list = (Car *)malloc(nCars * sizeof(Car)); // works in g++, not VC++
list[0].model = get_model();
std::cout << "model=" << list[0].model << std::endl;
// delete[] list;
free(list);
return 0;
}
There is no problem when I used malloc() or new in g++. However, malloc() does not work in Visual C++. Should I use new always when I allocate the C++ class object?
(a debtor)<><
You are allocating memory without calling a constructor or calling the destructor when the object is about to be removed. This is what new[] and delete[] does for you, so use them - or better yet, use smart pointers - or even better, a standard container, like std::vector to keep the objects for you.
Your code with the missing parts added:
#include <iostream>
#include <string>
struct Car {
std::string model;
Car() { std::cout << "ctor\n"; }
~Car() { std::cout << "dtor\n"; }
};
int main() {
const int nCars = 2;
// allocate memory
Car *list = (Car *)malloc(nCars * sizeof(Car));
// manually calling constructors
for(int i=0; i<nCars; ++i) {
new(&list[i]) Car();
}
// use objects here
// manually calling destructors
for(int i=0; i<nCars; ++i) {
list[i].~Car();
}
// freeing memory
free(list);
}
Compare with using new[] and delete[]:
int main() {
const int nCars = 2;
// create cars
Car* list = new Car[nCars];
// use objects here
// delete cars
delete[] list;
}
Compare with using a container:
int main() {
const int nCars = 2;
// create cars
std::vector<Car> list(nCars);
// use objects here
}
Yes.
While it is wrong to say, "Never use malloc() in C++," it is definitely true that you should never use malloc() to instantiate a class.
Keep in mind that C++ is, in a sense, a hybrid language in that it effectively supports an almost complete subset of C and adds the superset of C++ functionality. malloc() has a role to play when using built-in types like int, char, float, etc.
For objects, however, new must be used. It might be true that you have found that malloc() works in many cases, but new and delete will cause constructors and destructors to be called, which will never happen with malloc() and free().
The problem here is because you're allocating a memory for the std::string of your Car struct but do not call the std::string constructor.
You should call a placement new for each item in the array to call the constructor and initialize the std::string field in the Car struct:
int main() {
const int nCars = 2;
Car* list = (Car *)malloc(nCars * sizeof(Car));
for (int i = 0; i < nCars; ++i)
new(&list[i])Car();
list[0].model = get_model();
std::cout << "model=" << list[0].model << std::endl;
}
-- ORIGINAL ANSWER --
Here's my original answer (which is inorrect due to an extra overhead that may be required for arrays: https://en.cppreference.com/w/cpp/language/new#Allocation)
If you have to use malloc then I suggest you use a in-place constructor with the returned memory block:
int main() {
const int nCars = 2;
Car *list = new (malloc(nCars * sizeof(Car)))Car[nCars];
list[0].model = get_model();
std::cout << "model=" << list[0].model << std::endl;
return 0;
}
class book{
private:
int numOfPages;
public:
book(int i){
numOfPages = i;
};
};
class library{
private:
book * arrOfBooks;
public:
library(int x, int y){
arrOfBooks = new book[x](y);
};
};
int main()
{
library(2, 4);
};
With the example code above I would like to create a library of books that all have the same number of pages. So in the constructor of the library object, whenever a new book is created to be placed in the array I pass the argument in the parenthesis.
The above code when tested in C++ shell shows error: "parenthesized initializer in array new".
This is for the completion of a school project and no vectors are allowed (as it would be wise to do as I found doing my research) though I cannot think of any other ways to do it than the one shown above...
There is no syntax for initializing elements of a dynamic array using a non-default constructor.
You have to create the array first, then loop over the elements and assign each individually. Possibly the simplest way to do that is to use std::fill.
Array of books is a one dimensional array and it should be defined as follows:
library(int x)
{
arrOfBooks = new book[x];
};
If you have an assumption all books have same page you have pass it as a default parameter to your book class constructor:
book(int i=200)//set the defautlt value here
{
numOfPages = i;
};
Using templates:
#include <iostream>
template <int book_capacity> class book
{
private:
int numOfPages;
public:
book(): numOfPages(book_capacity){}
};
template <int lib_capacity, int book_capacity> class library
{
private:
book<book_capacity> arrOfBooks[lib_capacity];
int cnt;
public:
library(): cnt(0) {}
void addBook(book<book_capacity> b)
{
if (cnt < lib_capacity)
{
arrOfBooks[cnt] = b;
cnt++;
std::cout << "book is added" << std::endl;
return;
}
std::cout << "library is full" << std::endl;
}
};
int main()
{
library<2, 4> lib;
book<4> b;
lib.addBook(b);
lib.addBook(b);
lib.addBook(b);
lib.addBook(b);
system("pause");
return 0;
}
I am trying to swap the content in the arrays by swapping the pointers pointing to the two arrays.
My method is the same as what Daniel answered in this question: Swap arrays by using pointers in C++. But the difference is that my array will be a member in a class.
My code can be compiled successfully, but the output results are quite weird.
This is my header file:
#include <stdio.h>
#include <iostream>
class Map
{
public:
Map(int times); // Create an empty map (i.e., one with no key/value pairs)
int size(); // Return the number of key/value pairs in the map.
void dump();
void swap(Map &other);
int *retrieve();
void setptr(int *newptr);
private:
int *ptr;
int array_1[5];
};
Here is my implementation:
#include "Map.h"
#include <iostream>
using namespace std;
Map::Map(int times) {
for (int i = 0; i < 5; i++) {
array_1[i]=i*times;
}
ptr=array_1;
}
void Map::dump() {
ptr=array_1;
for (int i = 0; i < 5; i++) {
cout << *ptr << endl;
ptr++;
}
for (int i = 0; i < 5; i++) {
ptr--;
}
}
void Map::swap(Map &other) {
int *temp;
temp = this->ptr;
this->ptr = other.retrieve();
other.setptr(temp);
}
int *Map::retrieve() {
return ptr;
}
void Map::setptr(int *newptr) {
ptr=newptr;
}
Can anyone tell me what is wrong and how to implement it smartly?
The following code runs fine:
#include <stdio.h>
#include <iostream>
#include <conio.h>
using namespace std;
class Map
{
public:
Map(int times); // Create an empty map (i.e., one with no key/value pairs)
int size(); // Return the number of key/value pairs in the map.
void dump();
void swap(int &other);
int *retrieve();
void setptr(int *newptr);
private:
int *ptr;
int array_1[5];
};
Map::Map(int times){
for (int i=0;i<5;i++){
array_1[i]=i*times;
}
ptr=array_1;
}
void Map::dump(){
for (int i=0;i<5;i++)
{
cout<<ptr[i]<<endl;
}
}
void Map::swap(int &other){
int *temp;
temp=this->ptr;
this->ptr=&other;
other = *temp;
}
int *Map::retrieve(){
return ptr;
}
void Map::setptr(int *newptr){
ptr=newptr;
}
int main()
{
Map m(2);
Map n(3);
m.dump();
m.swap(*n.retrieve());
m.dump();
getchar();
}
1) Added a main function
2) Changed Swap function
But the problem that christopher pointed out will still persist i.e the pointer will point to an array in another object.
Edit: You probably need something like this:
void Map::swap(Map &other){
Map *temp;
temp=this;
*this = other;
other = *temp;
}
Map *Map::retrieve(){
return this;
}
Note: it is probably not elegant.
The problem with your design is that the pointer refers to an array in the same object.
Suppose you have to objects a and b. If you swap their pointers, a.ptr will point to b.array_1 which contains the data. reciprocally b.ptr will point to a.array1.
Unfortunately if one of the object -- say b -- gets destroyed (because it was a local object that goes out of scope, or for whatever reason) the pointer of the remaining object would point to an array which doesn't exist anymore. This is UB.
To solve your issue, you'd neet to allocate an array dynamically in the constructor. Get rid of array_1 completely:
Map::Map(int times){
ptr=new int[5]; // or better define a constant to avoid hard coded sizes
for (int i=0;i<5;i++){
ptr[i]=i*times;
}
}
Note that if you use pointers, you need to ensure the invarients on it. This means that you should define also the copy constructor and the assignment operator (to avoid the ptr to be blindly copied), as well as a destructor (to delete the dynamically allocated array).
P.S.: I suppose that you are learning C++ and are not yet familiar with vectors. These would avoid all the hassles here
Edit: if you experience your problem before any object is destroyed, it's because of a bad implementation of dump(): you increment the pointer there in, so that it will no longer point to the start of the array.
void Map::dump(){
for (int i=0;i<5;i++){
cout<<ptr[i]<<endl; // don't change ptr value !!
}
}
One simple trick to avoid such problems, is to systematically declare the member functions that are not supposed to change the state of the object as const:
class Map {
...
void dump() const;
...
}
Then the compiler issues an error if you try to accidentally change a member.
Should be a simple question, I have a struct
struct Foo{
float *bar;
Foo(){
bar = 0;
}
};
and a load function:
bool loadFoo(Foo *data){
float nums[4] = {0,1,2,3};
data->bar = nums;
return true;
};
And I run it like this:
void main(){
char data;
Foo myFoo;
loadFoo(&myFoo);
std::cerr << sizeof(myFoo.bar) << "\n";
std::cerr << myFoo.bar[0] << "\n";
std::cerr << myFoo.bar[1] << "\n";
std::cerr << myFoo.bar[2] << "\n";
std::cerr << myFoo.bar[3];
std::cin >> data;
};
and the output is 4 bytes for the sizeof(myFoo->bar) I thought by passing the struct to the method I could modify data->bar and since bar is, float *bar; I could make it an array since I cant specify that bar is an array because its an 'unknown size' when loaded. (when implemented the program will read in values from a file) This works fine with non pointer variables but its the pointer that I can't seem to understand.
How do I make it so that when I pass the struct I can modify the variable pointer?
any help would be greatly appreciated!
You can do something like you've specified, but the exact implementation you've given will encounter undefined behavior.
bool loadFoo(Foo *data){
// Create an array of 4 floats ON THE STACK.
float nums[4] = {0,1,2,3};
// point data->bar at the above slice of stack.
data->bar = nums;
return true;
// abandon the piece of stack we're pointing at.
}
You might want to look into std::vector as a growable way of storing runtime sizes arrays, or you will need to allocate backing store for the destination floats, e.g.
data->bar = new float[4];
and free it when you are done with it
delete data->bar;
That said; it would seem more elegant to do these operations as members of Foo.
#include <vector>
// #include <algorithm> // (for the std::copy option)
class Foo
{
std::vector<float> m_floats;
public:
Foo() : m_floats() {}
void loadFloats()
{
m_floats = { 0, 1, 2, 3 };
}
// or load them from someplace else
void loadFloats(float* srcFloats, size_t numFloats)
{
m_floats.clear();
m_floats.reserve(numFloats);
// copy by hand:
for (size_t i = 0; i < numFloats; ++i) {
m_floats.push_back(srcFloats[i]);
}
// or just:
// std::copy(srcFloats, srcFloats + numFloats, m_floats);
}
};
You haven't specified the problem but let me guess - it crashes and/or doesn't yield the result you expect. The reason for that is assigning a pointer to a local variable in the line data->bar = nums; Here you link your data->bar to a nums array which is allocated on stack and is freed when you exit loadFoo. The result is a dangling pointer inside your Foo object.
You can solve this in different ways. The most straightforward would be to use a constructor with size parameter - this will solve your unkonwn size issue. You'll need to explicitly allocate memory for the data->bar and copy the data into the allocated space (of course, it will require to free it when not in use anymore). Same effect can be achieved by using your loadFoo func but using internal language features (constructor/destructor) is much cleaner.
Instead of loadFoo you can have constructor
struct Foo{
float *bar;
Foo( int size){
bar = new float[size]; //allocate memory
//... Initialize bar
}
~Foo() { delete bar;}
};
OR using initializer_list
#include <initializer_list>
struct Foo{
float *bar;
Foo( std::initializer_list<float> l){
bar = new float[l.size()]; //allocate memory
std::initializer_list<float> ::iterator it = l.begin();
size_t i=0;
for(;it!=l.end();++it,++i)
bar[i] = *it;
}
~Foo() { delete bar;}
};
Also, make sure you follow rule of three
I have the following class in C++:
class a {
const int b[2];
// other stuff follows
// and here's the constructor
a(void);
}
The question is, how do I initialize b in the initialization list, given that I can't initialize it inside the body of the function of the constructor, because b is const?
This doesn't work:
a::a(void) :
b([2,3])
{
// other initialization stuff
}
Edit: The case in point is when I can have different values for b for different instances, but the values are known to be constant for the lifetime of the instance.
With C++11 the answer to this question has now changed and you can in fact do:
struct a {
const int b[2];
// other bits follow
// and here's the constructor
a();
};
a::a() :
b{2,3}
{
// other constructor work
}
int main() {
a a;
}
Like the others said, ISO C++ doesn't support that. But you can workaround it. Just use std::vector instead.
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
It is not possible in the current standard. I believe you'll be able to do this in C++0x using initializer lists (see A Brief Look at C++0x, by Bjarne Stroustrup, for more information about initializer lists and other nice C++0x features).
std::vector uses the heap. Geez, what a waste that would be just for the sake of a const sanity-check. The point of std::vector is dynamic growth at run-time, not any old syntax checking that should be done at compile-time. If you're not going to grow then create a class to wrap a normal array.
#include <stdio.h>
template <class Type, size_t MaxLength>
class ConstFixedSizeArrayFiller {
private:
size_t length;
public:
ConstFixedSizeArrayFiller() : length(0) {
}
virtual ~ConstFixedSizeArrayFiller() {
}
virtual void Fill(Type *array) = 0;
protected:
void add_element(Type *array, const Type & element)
{
if(length >= MaxLength) {
// todo: throw more appropriate out-of-bounds exception
throw 0;
}
array[length] = element;
length++;
}
};
template <class Type, size_t Length>
class ConstFixedSizeArray {
private:
Type array[Length];
public:
explicit ConstFixedSizeArray(
ConstFixedSizeArrayFiller<Type, Length> & filler
) {
filler.Fill(array);
}
const Type *Array() const {
return array;
}
size_t ArrayLength() const {
return Length;
}
};
class a {
private:
class b_filler : public ConstFixedSizeArrayFiller<int, 2> {
public:
virtual ~b_filler() {
}
virtual void Fill(int *array) {
add_element(array, 87);
add_element(array, 96);
}
};
const ConstFixedSizeArray<int, 2> b;
public:
a(void) : b(b_filler()) {
}
void print_items() {
size_t i;
for(i = 0; i < b.ArrayLength(); i++)
{
printf("%d\n", b.Array()[i]);
}
}
};
int main()
{
a x;
x.print_items();
return 0;
}
ConstFixedSizeArrayFiller and ConstFixedSizeArray are reusable.
The first allows run-time bounds checking while initializing the array (same as a vector might), which can later become const after this initialization.
The second allows the array to be allocated inside another object, which could be on the heap or simply the stack if that's where the object is. There's no waste of time allocating from the heap. It also performs compile-time const checking on the array.
b_filler is a tiny private class to provide the initialization values. The size of the array is checked at compile-time with the template arguments, so there's no chance of going out of bounds.
I'm sure there are more exotic ways to modify this. This is an initial stab. I think you can pretty much make up for any of the compiler's shortcoming with classes.
ISO standard C++ doesn't let you do this. If it did, the syntax would probably be:
a::a(void) :
b({2,3})
{
// other initialization stuff
}
Or something along those lines. From your question it actually sounds like what you want is a constant class (aka static) member that is the array. C++ does let you do this. Like so:
#include <iostream>
class A
{
public:
A();
static const int a[2];
};
const int A::a[2] = {0, 1};
A::A()
{
}
int main (int argc, char * const argv[])
{
std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n";
return 0;
}
The output being:
A::a => 0, 1
Now of course since this is a static class member it is the same for every instance of class A. If that is not what you want, ie you want each instance of A to have different element values in the array a then you're making the mistake of trying to make the array const to begin with. You should just be doing this:
#include <iostream>
class A
{
public:
A();
int a[2];
};
A::A()
{
a[0] = 9; // or some calculation
a[1] = 10; // or some calculation
}
int main (int argc, char * const argv[])
{
A v;
std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n";
return 0;
}
Where I've a constant array, it's always been done as static. If you can accept that, this code should compile and run.
#include <stdio.h>
#include <stdlib.h>
class a {
static const int b[2];
public:
a(void) {
for(int i = 0; i < 2; i++) {
printf("b[%d] = [%d]\n", i, b[i]);
}
}
};
const int a::b[2] = { 4, 2 };
int main(int argc, char **argv)
{
a foo;
return 0;
}
You can't do that from the initialization list,
Have a look at this:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
:)
A solution without using the heap with std::vector is to use boost::array, though you can't initialize array members directly in the constructor.
#include <boost/array.hpp>
const boost::array<int, 2> aa={ { 2, 3} };
class A {
const boost::array<int, 2> b;
A():b(aa){};
};
How about emulating a const array via an accessor function? It's non-static (as you requested), and it doesn't require stl or any other library:
class a {
int privateB[2];
public:
a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; }
int b(const int idx) { return privateB[idx]; }
}
Because a::privateB is private, it is effectively constant outside a::, and you can access it similar to an array, e.g.
a aobj(2,3); // initialize "constant array" b[]
n = aobj.b(1); // read b[1] (write impossible from here)
If you are willing to use a pair of classes, you could additionally protect privateB from member functions. This could be done by inheriting a; but I think I prefer John Harrison's comp.lang.c++ post using a const class.
interestingly, in C# you have the keyword const that translates to C++'s static const, as opposed to readonly which can be only set at constructors and initializations, even by non-constants, ex:
readonly DateTime a = DateTime.Now;
I agree, if you have a const pre-defined array you might as well make it static.
At that point you can use this interesting syntax:
//in header file
class a{
static const int SIZE;
static const char array[][10];
};
//in cpp file:
const int a::SIZE = 5;
const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};
however, I did not find a way around the constant '10'. The reason is clear though, it needs it to know how to perform accessing to the array. A possible alternative is to use #define, but I dislike that method and I #undef at the end of the header, with a comment to edit there at CPP as well in case if a change.