Here it is my code. I don't get it why it doesn't print 3, even though in the class constructor param1 becomes 3.
#include <iostream>
using namespace std;
class A{
int valoare;
public:
A(int param1 = 3):valoare(param1){}
int getValoare(){return this -> valoare;}
};
int main()
{
A vector[] = {*(new A(3)), *(new A(4)), *(new A(5)), *(new A(6))};
cout << vector[2].getValoare();
return 0;
}
You might want to read about default arguments: https://en.cppreference.com/w/cpp/language/default_arguments
When you specify an argument for a function with a defualt argument it overrides that default value. Thus, your code will print out 5.
As a side note, your code has a memory leak becuase you allocated memory with the new keyword and never deleted it. You should change the declaration of your Vector, that is, allocate memory on the stack like follows:
Vector = {A(3), A(4), A(5), A(6)}
The element at index 2 in the vector was constructed as A(5), so it's value ("valoare") is 5. The = 3 in the function definition is a default argument - which is used if you don't specify one yourself. So if you were to write:
std::cout << A().getValoare();
that would print 3.
But a few more observations are in order:
Prefer English-language names. valoare means "value" in some Latin or European language, right? Romanian perhaps? But - people who don't speak that language won't know that. Since you have to know English to program anyways, that's a safe choice for names.
Try not to use names for variables which are also names of classes in a different namespace. For example, your vector has the same name as std::vector, a class, or rather a class template, in the standard library. Try vec or my_vector or something else that's more distinctive.
You're leaking memory! Why are you using new to create values? Just use the construct, i.e.
A vector[] = { A(3), A(4), A(5), A(6) };
is just fine.
More generally, you should avoid calling new and delete explicitly, and instead prefer RAII-style classes - which allocate on construction and deallocate on destruction. The simplest thing to do is to switch to using smart pointers
Why the parameter doesn't change in the class constructor?
It doesn't print the value 3 because you're giving it another value.
from cppreference:
Default arguments are used in place of the missing trailing arguments in a function call:
void point(int x = 3, int y = 4);
point(1,2); // calls point(1,2)
point(1); // calls point(1,4)
point(); // calls point(3,4)
Related
I have a class lets say aClass
class aClass
{
public:
int data;
aClass(): data(-1) { //default constructor
}
aClass(int x): data(x) { //int constructor
};
If I create an array like
aClass* arr=new aClass[10];
Question 1:
I was thinking no aClass object has been created since it is just a declaration of an array, but in a program that I tested it looks like arr[0] to arr[9] all points to a aClass object created by default constructor in its class? Because I had tested the program and the result is a[0].data=-1 all the way to a[9].data=-1.
Question 2: if objects are created with their default constructor, how am I supposed to create an array that has objects created by int constructor? obviously I can't write code like
aClass* arr=new aClass(2015)[10];
Quesntion 1: I was thinking no aClass object has been created since it is just a declaration of an array
You were thinking wrong. It's a declaration of a pointer which is initialized with the return value of new aClass[10] which constructs an array of 10 objects.
but in a program that I tested it looks like arr[0] to arr[9] all points to a aClass object created by default constructor in its class?
Yes, your observation is correct.
Question 2: if objects are created with their default constructor, how am I supposed to create an array that has objects created by int constructor?
Since c++11 you can use list initialization: aClass *foo = new aClass[3]{1, 2, 3}; as chris pointed in a comment.
You may want to use std::vector instead. There is std::vector::vector(size_type n, const value_type& val) for constructing copies and since c++11: std::vector::vector(initializer_list<value_type>) for different values.
With static/automatic arrays aggregate initialization was possible even before c++11:
aClass foo[3] = { 1, 2, 3 };
Instead of aClass* arr=new aClass(2015)[10];
You could do aClass *arr = new aClass[10]{2015, 2015/*etc*/}; if your compiler supports it.
In C++11, both of these mean the same thing.
aClass *arr = new aClass[10];
aClass *arr = new aClass[10]{};
Better alternative would be to use std::vector and avoid using raw pointers and instead use smart pointers ex. std::unique_ptr.
Example of this alternative could be:
int main()
{
vector<unique_ptr<aClass>> vec;
for (int i{0}; i != 10; ++i)
vec.emplace_back(new aClass(2015));
for (auto const& i : vec) // print data
cout << i->data << endl;
return 0;
}
Regarding question 1. The rules for initialization are very rigid. Your array new[] expression creates an array of values. Those values must be initialized and by default they use default initialization.
The answer to question 2 is that you can't do that with dynamic arrays. However, std::vector does provide a constructor that allows you to provide an object that will be copied to each of the contained elements. See explicit vector(size_type count, const T& value = T(), const Allocator& alloc = Allocator()).
If you want each element in the collection to be different, then you must use a loop and assign the elements individually unless the size of the array is determined statically in which case you can use initializer expressions. If you want to avoid the initial default construction for dynamic containers, then you should not store the objects by value. You should use a container of pointers or better yet a container of smart pointers. Then you can use direct initialization for each object.
You need to create array of pointers if you want to create an array without creating the objects. For example, aClass** arr = new aClass*[10]; creates an array of pointers. And when you want to create the actual objects, you need to do something like this: arr[0] = new aClass(2015);
I've learned that if you declare for example an int in the global scope,
int x; //defaults to 0;
and in the local scope,
void f() {
int x; //undefined
}
However if we use a vector either in the global or local scope:
vector<int> v(3); //initialise v to {0,0,0} using int's default constructor.
We can default initialise int like vector's elements in the local scope by doing this:
int x = int(); //defaults to 0
I think if we use int's default constructor it's allocated in the heap.
Why can't a primitive type be default initialised in the local scope like T x;? Or
In the local scope, why does vectors (dunno about other containers) use the element's default constructor and not leave them uninitialised just like an int declaration?
What are the benefits of current approach on those two types? Why are they initialised in different ways? Is this about performance?
It's like this for "performance" reasons, because the C++ folks wanted the C folks back in the 1980's to not have any reason to complain about "paying for what we don't need." That's one of the tenets of C++, to not pay (run-time) costs for things you don't use. So the old-style POD types are uninitialized by default, though classes and structs with constructors always have one of those constructors called.
If I were specifying it today, I'd say that int x; in local scope would be default-initialized (to 0), and if you wanted to avoid that you could say something like int x = std::noinit;. It's far too late for this now, but I have actually done it in some class types when performance mattered a lot:
class SuperFast
{
struct no_init_t {};
public:
no_init_t no_init;
SuperFast() : x(0), y(0) {}
SuperFast(no_init_t) {}
private:
int x, y;
};
This way, default construction will give a valid object, but if you have a serious reason to need to avoid this, you can. You might use this technique if you know you will soon overwrite a whole bunch of these objects anyway--no need to default-construct them:
SuperFast sf(SuperFast::no_init); // look ma, I saved two nanoseconds!
Say I have a header file that looks like:
# filename: header.h
class myclass
{
public:
int myVariable; # arbitrary member variable
foo(); # arbitrary function
myclass() # default constructor
}
Now lets say I want to implement my constructor [ myclass() ] in some .cpp file:
Can I do something like create an array, of objects, ints, anything - just some array.
And then can I loop through that array and fill it up all from within my constructor definition?
The reason I ask is because I want my arbitrary member function foo() to be able to change this array. This leads to the problem - am I passing an object of myclass into foo [ foo(myclass myclassObject) ?
Or do I pass this object's array into foo() ?
Any clarification on this would be much appreciated. I tried to make the example as non-specific to a certain case as possible, but still descriptive enough for everyone to understand the problem. Thank you!
Yes, you can create and "fill up" an array from within the constructor so it can be used by foo. Indeed, that is the purpose of the constructor (to set up everything for you).
Do note that if you want foo() to be able to use the array, you must make the array part of the class definition.
myclass.h
class myclass {
private:
int* arr; // declared on the "heap"
public:
foo();
myclass(int arraySize);
};
myclass.cpp
#include "myclass.h"
#include <stdio>
myclass::myclass(int arraySize) :arr(new int[arraySize]) {}
myclass::foo() {
// prints the elements of the array we declared earlier
for (int i = 0; i < 5; i++) {
std::cout << arr[i] << std::endl;
}
}
Your constructor can indeed create an array - the question is what happens to that array after the constructor returns.
A reasonable approach is to save it on the heap - i.e. create the array with new[] - but that means you'll need to keep a pointer to the array to access it afterwards. Easiest way to do that is to add a pointer object to your class member data. foo() can then access the array using that pointer. Unfortunately, you must use either custom copy constructors, assignment operators and destructor (google Rule of Three) or a smart pointer to ensure proper copying or sharing and destruction of the array.
Your question implies to me that you don't just want an array data member, which is of course the easiest solution. Disadvantages with that are that the array size must be chosen at compile time, whereas heap based arrays can be sized at runtime.
If you create it on the stack, then it will leave scope and be inaccessible afterwards (any attempt to access it via pointers or references set while it was in scope will result in undefined behaviour).
It's also possible for a constructor to populate data in a static array, but clearly the array's lifetime is then independent of any single object instance of the class. You've talked about the constructor creating the array so presumably don't want to do this.
I noticed that when you declare an array, the default constructor must be needed. Is that right?
Is there any exception?
For example,
struct Foo{
Foo(int i ) {}
};
int main () {
Foo f[5];
return 0;
}
The code above does not compile.
Other answers are all right but, for completeness: You could also use the array initialization syntax:
Foo f[5] = {1,2,3,4,5};
This works if Foo's ctor is not explicit. If it was, you'd have to be.... explicit:
Foo f[5] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
Note1: There is a difference between the two cases that may not be obvious and is thus worth noting: In the first, the array elements are directly constructed from the ints in the initialization list, by invoking the Foo(int) ctor. In the second, the initialization list is made of Foos constructed with the explicit Foo(int) ctor, and the array elements are copy constructed from the elements in the initialization list. A copy ctor for Foo is thus required in the latter case.
[1] Thanks to MSalters for the comment.
The issue has nothing to do with arrays at all.
When you default-initialize an object of class type, the default constructor is required. If your class has no default constructor, then you have no other choice but to supply an explicit initializer when creating objects of that class. That's all.
By declaring a non-default constructor in your class Foo, you disabled the implicit generation of the default one, so now you'll have to supply an initializer every time you create a Foo object, regardless of whether it is an array element or not.
This declaration
Foo f; // ERROR
is not an array, but it will not compile for the very same reason. In order for it to compile you'll have to supply an explicit initializer
Foo f(3); // OK
The same thing happens with array, except that in that case you have to supply an initializer for each element using the aggregate initializer syntax
Foo f[5] = { 1, 2, 3, 4, 5 };
Of course, if you end up in a context where aggregate initializer syntax is not allowed (in the current version of C++ standard), like constructor initializer list or new-expression, then you are indeed screwed. In such contexts the only way out is to provide the default constructor in array element type (as long as you stick with built-in arrays).
That code doesn't compile because the compiler doesn't know what you want to pass to the constructor of each element, of course. There are basically two ways to go about it:
Make the array a vector, and pass it the desired size plus a single element -- this gives each element the same argument.
Make the array an array of pointers, and construct each element using a for loop and the new operator. The drawback of course, is that you have to free each element later as well.
See the C++ FAQ Lite, section 10.5
When you create an array, the default constructor gets called for each element in the array.
"If your class doesn't have a default constructor, you'll get a compile-time error when you attempt to create an array "
Prefer to use std::vector instead of the built-in arrays, though.
There is no exception. In what could be seen as exception, there is a compiler declared default constructor.
Note that a default constructor is not required if you use std::vector instead of an array - you can specify the constructor to be used:
std::vector <Foo> f; // OK
std::vector <Foo> f( 5, Foo(0) ); // also OK
No it doesn't.
An array, in C/C++ is a block of memory. Creating an array is reserving that block. Creating the objects is "1. Allocating the space 2. Running the constructors on each block" So, if you have an object without a constructor, you can still make an array of it (since that object has a size and since memory understands "size").
In short, it doesn't make any difference whatsoever. You will be running the constructors as you create the objects to fill the array with, or as said previously, when you assign it to something (which in turn, allocates space, runs the constructor).
Yes, you need the default constructor here because Foo f[5]; actually creates 5 Foos. You can work around this by making it a Foo* f[5] and then creating the 5 Foos with new.
For example:
Foo* f[5];
for(int i = 0; i < 5; ++i) {
f[i] = new Foo(i);
}
// later on...
f[0]->whatever();
Warning: slightly off-topic.
If you have a class without default constructor, you absolutely need to have an array, and you don't want to incur into the overhead of dynamic memory allocation, you can use an array of boost::optionals:
boost::optional<Foo> foos[4]; // Stack storage allocated but no objects
// constructed (roughly equivalent to what
// you get with vector<T>::reserve)
if(foos[2]) // Check if the third element has been constructed
{
foos[2]->bar(); // Access members of Foo with arrow
}
foos[1] = Foo(1, "a"); // Constructs the second element
foos[1].reset(); // Destroy second element (storage remains there though)
Unfortunately, you won't be able to pass this to a function expecting a true Foo[].
After reading a question on the difference between pointers and references, I decided that I'd like to use references instead of pointers for my class fields. However it seems that this is not possible, because they cannot be declared uninitialized (right?).
In the particular scenario I'm working on right now, I don't want to use normal variables (what's the correct term for them by the way?) because they're automatically initialized when I declare them.
In my snippet, bar1 is automatically instantiated with the default constructor (which isn't what I want), &bar2 causes a compiler error because you can't use uninitialized references (correct?), and *bar3 is happy as larry because pointers can be declared uninitialized (by the way, is it best practice to set this to NULL?).
class Foo
{
public:
Bar bar1;
Bar &bar2;
Bar *bar3;
}
It looks like I have to use pointers in this scenario, is this true? Also, what's the best way of using the variable? The -> syntax is a bit cumbersome... Tough luck? What about smart pointers, etc? Is this relevant?
Update 1:
After attempting to implement a reference variable field in my class and initializing it in the constructor, why might I receive the following error?
../src/textures/VTexture.cpp: In constructor ‘vimrid::textures::VTexture::VTexture()’:
../src/textures/VTexture.cpp:19: error: uninitialized reference member ‘vimrid::textures::VTexture::image’
Here's the real code:
// VTexture.h
class VTexture
{
public:
VTexture(vimrid::imaging::ImageMatrix &rImage);
private:
vimrid::imaging::ImageMatrix ℑ
}
// VTexture.cpp
VTexture::VTexture(ImageMatrix &rImage)
: image(rImage)
{
}
I've also tried doing this in the header, but no luck (I get the same error).
// VTexture.h
class VTexture
{
public:
VTexture(vimrid::imaging::ImageMatrix &rimage) : image(rImage) { }
}
Update 2:
Fred Larson - Yes! There is a default constructor; I neglected it because I thought it wasn't relevant to the problem (how foolish of me). After removing the default constructor I caused a compiler error because the class is used with a std::vector which requires there to be a default constructor. So it looks like I must use a default constructor, and therefore must use a pointer. Shame... or is it? :)
Answer to Question 1:
However it seems that this is not possible, because they [references] cannot be declared uninitialized (right?).
Right.
Answer to Question 2:
In my snippet, bar1 is automatically
instantiated with the default
constructor (which isn't what I want),
&bar2 causes a compiler error because
you can't use uninitialized references
(correct?),
You initialize references of your class in your constructor's initializer list:
class Foo
{
public:
Foo(Bar &rBar) : bar2(rBar), bar3(NULL)
{
}
Bar bar1;
Bar &bar2;
Bar *bar3;
}
Answer to Question 3:
In the particular scenario I'm working
on right now, I don't want to use
normal variables (what's the correct
term for them by the way?)
There is no correct name for them, typically you can just say pointers for most discussions (except this one) and everything you need to discuss will also apply to references. You initialize non pointer, non reference members in the same way via the initailizer list.
class Foo
{
public:
Foo() : x(0), y(4)
{
}
int x, y;
};
Answer to Question 4:
pointers can be declared uninitialized
(by the way, is it best practice to
set this to NULL?).
They can be declared uninitialized yes. It is better to initialize them to NULL because then you can check if they are valid.
int *p = NULL;
//...
//Later in code
if(p)
{
//Do something with p
}
Answer to Question 5:
It looks like I have to use pointers
in this scenario, is this true? Also,
what's the best way of using the
variable?
You can use either pointers or references, but references cannot be re-assigned and references cannot be NULL. A pointer is just like any other variable, like an int, but it holds a memory address. An array is an aliased name for another variable.
A pointer has its own memory address, whereas an array should be seen as sharing the address of the variable it references.
With a reference, after it is initialized and declared, you use it just like you would have used the variable it references. There is no special syntax.
With a pointer, to access the value at the address it holds, you have to dereference the pointer. You do this by putting a * before it.
int x=0;
int *p = &x;//p holds the address of x
int &r(x);//r is a reference to x
//From this point *p == r == x
*p = 3;//change x to 3
r = 4;//change x to 4
//Up until now
int y=0;
p = &y;//p now holds the address of y instead.
Answer to Question 6:
What about smart pointers, etc? Is
this relevant?
Smart pointers (See boost::shared_ptr) are used so that when you allocate on the heap, you do not need to manually free your memory. None of the examples I gave above allocated on the heap. Here is an example where the use of smart pointers would have helped.
void createANewFooAndCallOneOfItsMethods(Bar &bar)
{
Foo *p = new Foo(bar);
p->f();
//The memory for p is never freed here, but if you would have used a smart pointer then it would have been freed here.
}
Answer to Question 7:
Update 1:
After attempting to implement a
reference variable field in my class
and initializing it in the
constructor, why might I receive the
following error?
The problem is that you didn't specify an initializer list. See my answer to question 2 above. Everything after the colon :
class VTexture
{
public:
VTexture(vimrid::imaging::ImageMatrix &rImage)
: image(rImage)
{
}
private:
vimrid::imaging::ImageMatrix ℑ
}
They can be initialized. You just have to use the member initializer list.
Foo::Foo(...) : bar1(...), bar2(...), bar3(...)
{
// Whatever
}
It's a good idea to initialize all of your member variables this way. Otherwise, for other than primitive types, C++ will initialize them with a default constructor anyway. Assigning them within the braces is actually reassigning them, not initializing them.
Also, keep in mind that the member initializer list specifies HOW to initialize the member variables, NOT THE ORDER. Members are initialized in the order in which they are declared, not in the order of the initializers.
Use the null object design pattern
I'm using ints but it would be the same with any type.
//header file
class Foo
{
public:
Foo( void );
Foo( int& i );
private:
int& m_int;
};
//source file
static int s_null_Foo_m_i;
Foo::Foo( void ) :
m_i(s_null_Foo_m_i)
{ }
Foo::Foo( int& i ) :
m_i(i)
{ }
Now you have to make sure that Foo makes sense when default constructed. You can even detect when Foo has been default constructed.
bool Foo::default_constructed( void )
{
return &m_i == &s_null_Foo_m_i;
}
I absolutely agree with the sentiment, Always prefer references over pointers. There are two notable cases where you can't get away with a reference member:
Null has a meaningful value.
This can be avoided with the null object design pattern.
The class has to be assignable.
The compiler will not generate an assignment operator for classes that have a reference member. You can define one yourself, but you will not be able to change where the reference is bound.
There is also a side effect when you define when you define Bar and Bar *
class Foo
{
public:
Bar bar1; // Here, you create a dependency on the definition of Bar, so the header //file for bar always needs to be included.
Bar &bar2;
Bar *bar3; //Here, you create a pointer, and a forward declaration is enough, you don't have to always include the header files for Bar , which is preferred.
}
Using references just because the -> syntax is cumbersome isn't the best reason... References have the one great advatage over pointers in that nulls aren't possible without casting trickery, but also disadvantages in initialization and the risk of accidentally illegaly binding temporaries which then go out of scope (for instance, after an implicit conversion).
Yes, smart pointers such as the boost ones are almost always the right answer for handling composite members, and occasionally for associated members (shared_ptr).
class Foo {
public:
Bar bar1;
Bar &bar2;
Bar *bar3;
// member bar2 must have an initializer in the constructor
Bar::Bar(Bar& _bar2) : bar1(), bar2(_bar2), bar3(new Bar()) {}
Bar::~Bar() {delete bar3;}
}
Note that bar2 isn't just initialized in the ctor; it's initialized with a bar object that's passed in as a reference parameter. That object and the bar2 field will be bound together for the life of the new Foo object. That is usually a very bad idea, because it's hard to ensure that the lifetimes of the two objects will be well coordinated (i.e., that you will never dispose of the passed-in bar object before disposing of the Foo object.)
This is why it's greatly preferred to use either instance variables (as in bar1) or pointers to objects allocated on the heap (as in bar3.)