I'm learning how to create move constructors, so I made a class called Test that has one, just like the ones in the tutorials:
class Test {
private:
int* arr;
int size;
public:
Test() {
arr = new int[100];
size = 100;
for (int i = 0; i < 100; i++) {
arr[i] = i;
}
}
Test(Test&& other) {
arr = other.arr;
size = other.size;
other.arr = nullptr;
other.size = 0;
}
};
Out of curiosity, I removed the Rvalue reference to see if it worked with the "old reference":
class Test {
private:
int* arr;
int size;
public:
Test() {
arr = new int[100];
size = 100;
for (int i = 0; i < 100; i++) {
arr[i] = i;
}
}
Test(Test& other) {
arr = other.arr;
size = other.size;
other.arr = nullptr;
other.size = 0;
}
};
To my surprise, it worked perfectly. So my question is:
If we were able to build perfectly good move constructors before, why did they add this to the language?
With what you are suggesting, the same thing happens in the first and third case below:
Test someFunction();
Test a;
Test b(a); // 1. as a developer I wanted a copy
Test c(someFunction()); // 2. I expect the compiler to move the return value
Test d(std::move(a)); // 3. here, I wanted a move, as I don't care about a anymore
So, of the three cases above, your suggestion doesn't distinguish the first and third. This is what r-value reference offer: figuring out the context and distinguishing between references that can be moved and those that cannot.
I'd like to store an array of numbers in a private variable of a class using a setter method, but am unsure how to.
The program requires a default constructor, and the other essential methods but for simplicity i've only provided the default constructor.
class numberList{
public:
numberList()
{
numberStore = new int[8];
} // default constructor
void setter() // not sure what goes here
{
//not sure what goes here
}
private:
int* numberStore;
};
int main()
{
numberList list1;
list1.setter(1,2,3,4,5,6,7)
}
I'd like for the list1.setter() to take all the values to be put into the array. I think memcpy() could be used here, but am unsure.
I understand there's a concept of operator overloading, but am unsure how utilise this. Any help would be appreciated :-)
EDIT: the assignment requires me not to use standard libraries unfortunately :-(
From your comment that you can't use the STL the solution is to use raw C-pointer arithemtics.
To your setter function you can give a int* pointer and the number of elements:
void setter(int* arr, int n) {
for(int i = 0; i < n; i++)
numberStore[i] = arr[i]
}
Then you can call your setter function in main() like this:
int main() {
numberList list1;
int arr[] = {1,2,3,4,5,6,7};
list1.setter(arr, 7);
}
#include "pch.h"
#include <iostream>
#include <string>
int* my_array = new int[10];
void setter(int* arr, int n)
{
memcpy(&my_array[0], &arr[0], n * sizeof(int));
}
int main()
{
int* arry = new int[10];
for (int i=0; i< 10; i++)
{
arry[i] = i;
}
setter(arry, 10);
for (int i = 0; i < 10; i++)
{
std::cout<<(std::to_string(my_array[i]));
}
}
It might be that I have coded my class incorrectly, but when I use the move constructor instead of the copy cotr (as one of the overloads not instead to be precise), my program crushes:
For example:
class Sample
{
int a;
int **b;
//constructor declarations
}
And in the .cpp file:
Sample::Sample(Sample &&other)
: a(a), b(b)
{
for (int i = 0; i < a; i++)
other.b[i] = nullptr;
other.b = nullptr;
other.a = 0;
}
How to fix this issue?
Here is how you could move the values:
#include <utility>
#include <iostream>
class Sample
{
int a;
int **b;
public:
Sample(int a, int** b) : a{a}, b{b} {}
Sample(Sample &&other);
// still missing a destructor that will get rid of the new'd ints
void print();
};
Sample::Sample(Sample &&other)
: a(other.a), b(other.b)
{
//for(int i = 0; i < a; i++)
// other.b[i] = nullptr; // this should not be done, the new b has a pointer to these values
other.b = nullptr;
other.a = 0;
}
void Sample::print()
{
if(a == 0 && b == nullptr)
std::cout << "this object is empty!";
for(size_t i{0}; i < a; ++i) {
std::cout << *b[i] << " ";
}
std::cout << '\n';
}
int main()
{
Sample s{5,{new int*[5]{new int{0}, new int{1}, new int{2}, new int{3}, new int{4}}}};
auto c{std::move(s)};
// c now has c.b as a pointer an array of pointers
s.print();
c.print();
return 0;
}
Ill just recap my comment above and put it as an answer. You copied 'b' pointer but you modified the values that pointer points to. The new object will get correct pointer 'b' but the value that pointer points to is modified as well, in this case it will point to number zero. You are using pointer to a pointer so at some point your new object might try to dereference the pointers and as a result of a dereferencing a null pointer bad things happen.
#include <iostream>
class Car
{
private:
Car(){};
int _no;
public:
Car(int no)
{
_no=no;
}
void printNo()
{
std::cout<<_no<<std::endl;
}
};
void printCarNumbers(Car *cars, int length)
{
for(int i = 0; i<length;i++)
std::cout<<cars[i].printNo();
}
int main()
{
int userInput = 10;
Car *mycars = new Car[userInput];
for(int i =0;i < userInput;i++)
mycars[i]=new Car[i+1];
printCarNumbers(mycars,userInput);
return 0;
}
I want to create a car array but I get the following error:
cartest.cpp: In function ‘int main()’:
cartest.cpp:5: error: ‘Car::Car()’ is private
cartest.cpp:21: error: within this context
is there a way to make this initialization without making Car() constructor public?
You can use placement-new like this:
class Car
{
int _no;
public:
Car(int no) : _no(no)
{
}
};
int main()
{
void *raw_memory = operator new[](NUM_CARS * sizeof(Car));
Car *ptr = static_cast<Car *>(raw_memory);
for (int i = 0; i < NUM_CARS; ++i) {
new(&ptr[i]) Car(i);
}
// destruct in inverse order
for (int i = NUM_CARS - 1; i >= 0; --i) {
ptr[i].~Car();
}
operator delete[](raw_memory);
return 0;
}
Reference from More Effective C++ - Scott Meyers:
Item 4 - Avoid gratuitous default constructors
Nope.
But lo! If you use std::vector<Car>, like you should be (never ever use new[]), then you can specify exactly how elements should be constructed*.
*Well sort of. You can specify the value of which to make copies of.
Like this:
#include <iostream>
#include <vector>
class Car
{
private:
Car(); // if you don't use it, you can just declare it to make it private
int _no;
public:
Car(int no) :
_no(no)
{
// use an initialization list to initialize members,
// not the constructor body to assign them
}
void printNo()
{
// use whitespace, itmakesthingseasiertoread
std::cout << _no << std::endl;
}
};
int main()
{
int userInput = 10;
// first method: userInput copies of Car(5)
std::vector<Car> mycars(userInput, Car(5));
// second method:
std::vector<Car> mycars; // empty
mycars.reserve(userInput); // optional: reserve the memory upfront
for (int i = 0; i < userInput; ++i)
mycars.push_back(Car(i)); // ith element is a copy of this
// return 0 is implicit on main's with no return statement,
// useful for snippets and short code samples
}
With the additional function:
void printCarNumbers(Car *cars, int length)
{
for(int i = 0; i < length; i++) // whitespace! :)
std::cout << cars[i].printNo();
}
int main()
{
// ...
printCarNumbers(&mycars[0], mycars.size());
}
Note printCarNumbers really should be designed differently, to accept two iterators denoting a range.
You can create an array of pointers.
Car** mycars = new Car*[userInput];
for (int i=0; i<userInput; i++){
mycars[i] = new Car(...);
}
...
for (int i=0; i<userInput; i++){
delete mycars[i];
}
delete [] mycars;
or
Car() constructor does not need to be public. Add a static method to your class that builds an array:
static Car* makeArray(int length){
return new Car[length];
}
In C++11's std::vector you can instantiate elements in-place using emplace_back:
std::vector<Car> mycars;
for (int i = 0; i < userInput; ++i)
{
mycars.emplace_back(i + 1); // pass in Car() constructor arguments
}
Voila!
Car() default constructor never invoked.
Deletion will happen automatically when mycars goes out of scope.
No, there isn't. New-expression only allows default initialization or no initialization at all.
The workaround would be to allocate raw memory buffer using operator new[] and then construct objects in that buffer using placement-new with non-default constructor.
Good question. I had the same question, and found it here. The real answer is, #Dan-Paradox, there is no standard syntactical way of doing it. So, all these answers are a variety of alternatives to get around the problem.
I read the answers myself, and didn't particularly find any of them perfect for my personal convention. The method that I'll probably stick with is using a default constructor and a set method:
class MyClass
{
int x,y,z;
public:
MyClass(): x(0), y(0), z(0) {}
MyClass(int _x,int _y,int _z): x(_x), y(_y), z(_z) {} // for single declarations
void set(int _x,int _y,int _z)
{
x=_x;
y=_y;
z=_z;
}
};
The standard initialization constructor is still there, so I can still initialize it normally if I don't need more than one, but if otherwise, I have a set method which sets all the variables that are initialized in the constructor. Thus I could do something like this:
int len = 25;
MyClass list = new MyClass[len];
for(int i = 0; i < len; i++)
list[i].set(1, 2, 3);
This works fine and flows naturally, without making code look confusing.
Now that's my answer for those wondering how to declare an array of objects that need to be initialized.
For you specifically, you're trying to give an array of cars identities, which I'd suppose you want to always be unique. You could do it with my method I explained above, and then in the for loop use i+1 as the argument sent to the set method - but from what I've read in your comments, it seems like you want the ids more internally initiated, so that by default each Car has a unique id, even if someone else uses your class Car.
If this is what you want, you can use a static member:
class Car
{
static int current_id;
int id;
public:
Car(): id(current_id++) {}
int getId() { return id; }
};
int Car::current_id = 1;
// ...
int cars=10;
Car* carlist = new Car[cars];
for(int i = 0; i < cars; i++)
cout << carlist[i].getId() << " "; // prints "1 2 3 4 5 6 7 8 9 10"
In this way, you don't have to worry at all about initiating the identities since they are managed internally.
You can always create an array of pointers , pointing to car objects and then create objects, in a for loop, as you want and save their address in the array , for example :
#include <iostream>
class Car
{
private:
Car(){};
int _no;
public:
Car(int no)
{
_no=no;
}
void printNo()
{
std::cout<<_no<<std::endl;
}
};
void printCarNumbers(Car *cars, int length)
{
for(int i = 0; i<length;i++)
std::cout<<cars[i].printNo();
}
int main()
{
int userInput = 10;
Car **mycars = new Car*[userInput];
int i;
for(i=0;i<userInput;i++)
mycars[i] = new Car(i+1);
note new method !!!
printCarNumbers_new(mycars,userInput);
return 0;
}
All you have to change in new method is handling cars as pointers than static objects
in parameter and when calling method printNo()
for example :
void printCarNumbers_new(Car **cars, int length)
{
for(int i = 0; i<length;i++)
std::cout<<cars[i]->printNo();
}
at the end of main is good to delete all dynamicly allocated memory like this
for(i=0;i<userInput;i++)
delete mycars[i]; //deleting one obgject
delete[] mycars; //deleting array of objects
Hope I helped, cheers!
Noboby have commented the posibility of using an allocator for this task.
#include <iostream>
#include <memory>
class Car
{
private:
Car(){};
int _no;
public:
Car(int no)
{
_no=no;
}
void printNo()
{
std::cout<<_no<<std::endl;
}
};
void printCarNumbers(Car *cars, int length)
{
for(int i = 0; i<length;i++)
(cars+i)->printNo();
}
int main()
{
int userInput = 10;
std::allocator<Car> carAllocator;
// reserves space in memory for 10 car objects, but not construct them
Car *myCars = carAllocator.allocate(10);
Car *myCarsBegin = myCars; // begin of array myCars
for(int i =0; i < userInput; i++ ){
// effectively creates the class "Car" and initializes it
// myCars now points to the first car created
carAllocator.construct( myCars, i );
++myCars;
}
printCarNumbers(myCarsBegin,userInput);
// destroy the objects created
for( Car *carIterator = myCarsBegin; carIterator != myCars; ++carIterator )
carAllocator.destroy( carIterator );
return 0;
}
One way to solve is to give a static factory method to allocate the array if for some reason you want to give constructor private.
static Car* Car::CreateCarArray(int dimensions)
But why are you keeping one constructor public and other private?
But anyhow one more way is to declare the public constructor with default value
#define DEFAULT_CAR_INIT 0
Car::Car(int _no=DEFAULT_CAR_INIT);
Firstly I want to clarify that there is a bug in your code in printCarNumbers function, you are trying to send void to the standard output using std::cout as shown below :
void printCarNumbers(Car *cars, int length)
{
for(int i = 0; i < length; i++)
std::cout << cars[i].printNo();
}
since printNo() is used for printing then just call it directly:
for(int i = 0; i < length; i++)
cars[i].printNo();
let's return to the subject, you are trying to allocate an array of objects using new like this :
Car *mycars = new Car[userInput];
but with this syntax, you actually trying to allocate an array of objects that has userInput size (well that's what we want), but the problem is that it tries to call the default constructor for each object, and the default constructor is declared as private, so it can't find it, that's why you got that error :
cartest.cpp:5: error: ‘Car::Car()’ is private
instead of that you need to do it in this way :
Car *mycars = (Car*) ::operator new (sizeof(Car));
// allocates memory by calling: operator new (sizeof(Car))
// but does not call Car's constructor
as described in the comments, calling new in this way, allocates memory for you without calling the default constructor, for more details check new operator
and now if you want to call the parametrized constructors, you need to call it for each object separately as the following :
for(int i =0; i < userInput; i++)
new (&mycars[i]) Car(i + 1); // does not allocate memory -- calls: operator new (sizeof(Car), &mycars[i])
// but constructs an object at mycars[i]
you might be confused now, since we called new again, but this syntax for new is not allocating any memory, it's just calling the constructor of the indexed object.
and here is the full functioning code for anyone wants to test :
#include <iostream>
class Car
{
private:
Car(){};
int _no;
public:
Car(int no)
{
_no=no;
}
void printNo()
{
std::cout << _no << std::endl;
}
};
void printCarNumbers(Car *cars, int length)
{
for(int i = 0; i < length; i++)
cars[i].printNo();
}
int main()
{
int userInput = 10;
Car *mycars = (Car*) ::operator new (sizeof(Car));
for(int i =0;i < userInput;i++)
new (&mycars[i]) Car(i+1);
printCarNumbers(mycars,userInput);
return 0;
}
I know that I am so late, but maybe someone will find this useful, If there is any wrong statement, please be free to correct me.
You can use an array of optional<Car>, using optional from C++17.
#include <optional>
void printCarNumbers(std::optional<Car> *cars, int length) {
for (int i = 0; i < length; ++i)
cars[i]->printNo();
}
int main() {
int userInput = 10;
std::optional<Car> mycars[userInput];
for (int i = 0; i < userInput; ++i)
mycars[i].emplace(i);
printCarNumbers(mycars, userInput);
return 0;
}
I don't think there's type-safe method that can do what you want.
You can use in-place operator new. This would be a bit horrible, and I'd recommend keeping in a factory.
Car* createCars(unsigned number)
{
if (number == 0 )
return 0;
Car* cars = reinterpret_cast<Car*>(new char[sizeof(Car)* number]);
for(unsigned carId = 0;
carId != number;
++carId)
{
new(cars+carId) Car(carId);
}
return cars;
}
And define a corresponding destroy so as to match the new used in this.
My way
Car * cars;
// else were
extern Car * cars;
void main()
{
// COLORS == id
cars = new Car[3] {
Car(BLUE),
Car(RED),
Car(GREEN)
};
}
How do i can free mamory in next example.
vt.pop_back() deletes element in vt, but it doesn't free memory.
delete vt[i] doesn't work, and it give me segmentation fault.
#include <vector>
#include <unistd.h>
using namespace std;
const int SIZE = 1000000;
class Test
{
public:
Test();
~Test();
private:
int *arr;
};
int main()
{
vector<Test *> vt;
for(int i = 0; i < 100; i++)
vt.push_back(new Test());
sleep(10);
return 0;
}
Test::Test()
{
arr = new int[SIZE];
}
Test::~Test()
{
delete[] arr;
}
You are not storing "Test" objects, you are storing pointers to these objects. So delete does nothing but delete the pointers.
If you want your objects to be stored in the vector you should make the type
vector<Test>
This way the delete calls actually run the destructor of the objects.
The resulting code becomes:
int main()
{
vector<Test> vt;
for(int i = 0; i < 100; i++)
vt.push_back(Test());
sleep(10);
return 0;
}
As commented this also requires a new copy constructor:
Test::Test(const Test& t)
{
arr = new int[SIZE];
for(int i = 0; i != SIZE; i++)
arr[i] = t.arr[i];
}
You can use delete vt[i] like this, it will free the memory allocated to Test objects:
for(size_t i = 0; i < vt.size(); ++i)
{
delete vt[i];
}
vt.clear();
You are storing pointers and not objects, therefor the "pointer object" is going to be destroyed if you destroy your vector but not the object the pointer points to
If you want to delete specific elements, you could try using the function erase of std::vector.