i dont really get the fields of the template std::vector, the first one specifies the type, for example a class, but i dont get the allocator, pointer and reference variables.
i will provide a simple example, i want to use a vector of class person, so i have to say to the template vector: hey, store me some person's, but i also have to tell the vector how to allocate that class. (1)How would a correct syntax be for that example?
some code to start with:
side note, in the person's constructor,c(2)should i use date*?
class date
{
public:
int m_nMonth;
int m_nDay;
int m_nYear;
int getMonth(return m_nMonth;)
int getDay(return m_nDay;)
int getYear(return m_nYear;)
void setDate(int month, int day, int year)
{
m_nMonth=month;
m_nDay=day;
m_nYear=year;
}
date()
{
setDate(0,0,0);
}
date(int month, int day, int year)
{
setDate(month,day,year);
}
void printDate()
{
printf("%d/%d/%d", m_nMonth, m_nDay, m_nYear);
}
}
class person
{
public:
int m_nID;
char m_sName[128];
char m_sSurname[128];
date m_cBirthDay;
void setName(const char* name)
{
strncpy(m_sName, name, 127);
m_sName[127]= '\0';
}
void setSurname(const char* surname)
{
strncpy(m_sSurname, surname, 127);
m_sName[127]= '\0';
}
void setBirthDay(date* bday);
{
m_cBirthDay.date(bday.getMonth(), bday.getDay(), bday.getYear)
}
person(int id, const char* name, const char* surname, date bday)/*should it be date* bday? why?*/
{
m_nID=id;
setName(name);
setSurname(surname);
setBirthDay(bday);
}
}
i suppose you have to declare a function inside class person, called allocator, that is whats passed as second argument when you call, (3)how would that allocator function be defined?:
vector <person*, /*some allocator call*/> ImAVector;
then, (4)how could i push something in the vector, (5)would this work?:
person* someperson;
someperson.person(/*arguments*/);
ImAVector.push_back(someperson);
(6)how could i retrieve the pointer to a particular instance? (7)can i use the iterator to do something like this?:
//(6)
person* = ImAVector[someIterator];
//and then (7)
ImAVector[someIterator].setName(someConstCharPointer);
string* something = person.getName();
also, (8)does the allocator have anything to do with the constructor? (9)its common procedure to fill your class's fields right after allocating the instance of the class? (10)can an allocator call a constructor?
And the last questions: (11)what is the reference field, the pointer field, and their const counterparts?
I know its a lot to write, but ive spent the last two days searching for examples without success, so it would be nice if someone shed some light into this rarely discussed topic, ive numerated all questions for an easy response.
I appreciate any answers :)
How would a correct syntax be for that example?
Unless you have a good reason for storing pointers, don't. Then you just declare
std::vector<person> people;
// In C++11, you can create people in place
people.emplace_back(id, name, surname, birthday);
// Historically, you had to create a person and copy it in
people.push_back(person(id, name, surname, birthday));
and all the allocation is managed for you.
Reasons for wanting pointers include:
the vector is not supposed to manage the objects. In that case, you don't need to tell the vector how to allocate them.
perhaps person is a base class and you want to store various different subtypes.
In that case, I don't think you can use an allocator to help; instead, you could store smart pointers to automatically delete the objects when the pointer is removed from the container:
std::vector<std::unique_ptr<person>> people;
people.push_back(std::unique_ptr<person>(new person(id, name, surname, birthday)));
The alternative is to juggle raw pointers and try to delete the objects at the right time; but life's too short for that nonsense.
(2)should i use date*?
No. For a large or complicated class, it might be beneficial to pass a const reference, const date&; but this class is simple enough to pass by value. Passing a pointer would be weird, except in languages like C where that's the only way to pass by reference.
how could i retrieve the pointer to a particular instance?
people[index] gives a reference (not pointer) to the person with that index. If you really want a pointer for some reason, use & to take the address:
person & ref = people[index];
person * ptr = &ref;
can i use the iterator to do something like this?
No, [] is used to access by the array index, not to dereference an iterator. If you have an iterator it, then *it gives you a reference to the object.
does the allocator have anything to do with the constructor?
No, allocators are used if you have special memory-management requirements, and don't want the vector to simply allocate memory on the heap. There use is quite rare.
its common procedure to fill your class's fields right after allocating the instance of the class
It's common to initialise all the data members in the constructor, yes.
You don't need to specify anything other than the type.
vector<person> people;
people.emplace_back(/* constructor arguments for a person */); // constructs the person in place instead of copying into the vector.
person p;
p.stuff();
vector.push_back(p); // copies p into the vector
etc. Basically the defaults for allocator and the other fields are good enough, no need to specify them unless you have reason to override the default behavior. I've never had reason to do so.
Related
class Student {
private:
int age;
public:
char *name;
Student(int age,char*name) {
this->age=age;
this->name=new char[strlen(name)+1];
strcpy(this->name,name);
}
Student(Student const &s1) {
this->age=s1.age;
this->name=new char[strlen(s1.name)+1];
strcpy(this->name,s1.name);
s1.name[0]='x';
}
void display() {
cout<<age<<" "<<name<<endl;
}
};
int main() {
char name[]="abcd";
Student s1(10,name);
s1.display();
Student s2(s1);
s2.name[0]='x';
s1.display();
s2.display();
}
I have passed s1 as a constant reference but I am able to change s1.name[0] and the program compiles successfully. Why I am able to change s1.name[0]?enter image description here
You did not modify s1. You modified some unrelated memory block (allocated by new) , to which s1 holds a pointer. In C++ there is no special relationship between a raw pointer and any memory block it might happen to be pointing to.
If you use std::string instead of raw pointers and manual memory management then this problem will not arise.
As others have already said this is because s1 is const, so you cannot modify the pointer s1.name. However, the memory s1.name is pointing at is not const.
If you really cannot use std::string, you might want to have a look at std::experimental::propagate_const. This is a wrapper for any pointer type, in your case a raw pointer, that will, as the name suggests, propagate its constness to the memory it points at.
But as I can hardly imagine any circumstances where you are not able/allowed to use an std class (string), but an std::experimental class would be ok, this is likely not an option for you. However, you might get inspired by the idea and write your own string class.
Note in case you are not aware: you are missing a corresponding delete for your new. std::string would do that for you. So, if you write your own string class, make sure that one also does that.
I am new to C++ (more of a java guy). I am trying to teach myself about C++ pointers. Here I've created two classes, Person (The base class), and the Student (Derived class).
I tried to put Student objects in an unordered_map<string, Person>. But met an error.
This is my code:
class Person
{
protected:
string name;
int age;
public:
int getAge()
{
return age;
}
string getName()
{
return name;
}
};
class Student : public Person
{
private:
string grade;
public:
Student(string const &name, int const &age, string const &grade)
{
this -> name = name;
this -> age = age;
this -> grade = grade;
}
int getAge();
};
Here's my main function:
int main()
{
unordered_map<string, Person *> students;
Student s("Sam", 26, "A");
Person *p;
p = &s;
students.insert(p -> getName(), p);
return 0;
}
This is just a part of the code, and I know it looks foolish. But I'm just learning about pointers
I have included <iostream> and <unordered_map> libraries and using namespace std here.
Error message is so long. Can someone point out the error I made here ? Or, should I post that long error message also ?
Thanks in advance.
I am more of a java guy.
Here's what you need to know:
Pointers
Person* is a pointer to a person - a pointer simply carries the address of an object in memory. It's as low level as you can get. It's equivalent to using an address register or index register in assembly language. It carries no information about object lifetime and does not influence object lifetime in any way. It is 100% abusable. Use with care, if ever.
Shared references
// java code
var x = new Y();
var y = x;
// equivalent c++
auto x = std::make_shared<Y>();
auto y = x;
If you want java-like behaviour, then std::shared_ptr<Person> is equivalent to a java object reference. It shares ownership of the person and allows (actually in c++ mandates) that the Person is destroyed when all of the shared_ptrs have gone out of scope or have been reset.
Unique reference with lifetime control
Between the two is a std::unique_ptr<Person> which will cause the automatic destruction of the Person when the one and only unique_ptr is destroyed or reset. You cannot copy a std::unique_ptr so it can't be used to share references to an object. It can however, be converted to a shared_ptr (this implicitly empties the unique_ptr).
Weak references
Then there is a std::weak_ptr<Person> which is the weak counterpart to a std::shared_ptr<Person>. It cannot be de-referenced directly but must first be converted to a shared_ptr with the lock() method. This provides an atomic 'test for existence and lock into place' operation. We use it to resolve or avoid resource leaks caused by circular references (which java claims not to have on account of garbage collection).
Lifetime differences between Java and C++
In Java, when there are no more reachable references to an object, it becomes a candidates for garbage collection. At some point in the future, it may or may not be recovered.
C++ is different and more predictable. When the unique_ptr or the last shared_ptr controlling an object's lifetime is reset, that object's destructor will be executed immediately and in the same thread. It's completely sequential. This gives rise to the possibility of RAII, and allows us to use object lifetimes to cause code to execute no matter what the execution path.
This is also arguably why there is no need for finally in c++. Resource cleanup goes in the destructors of resource owners.
int main()
{
unordered_map<string, Person *> students;
Student s("Sam", 26, "A");
Person *p;
p = &s;
pair<string, Person*> item("key", p);
students.insert(item);
return 0;
}
Your code looks ok, except for one line:
students.insert(p -> getName(), p);
Here you probably meant that you want to place p to the cell p->getName(), but, unfortunately, std::unordered_map::insert has no instance to take a key and a value as two arguments. Passing them as one argument or using operator[] should help:
students[p->getName()] = p;
students.insert({p->getName(), p});
students.insert(std::make_pair(p->getName(), p));
I personally would select first option as more readable, if possible.
UP: As #Jarod42 commented, the first option here requires the value type to be default constructible, which is not always an option.
I have this constructor
Movie::Movie(char *&t, char *&d)
{
title = t;
director = d;
}
And in my main I have this:
Movie * movies = new Movie[movie_size];//creating array of class "Movie"
Movie *movieone=new Movie("MovieTitle", "Director");
movies[0]=movieone;
I get the following error:
no matching constructor for initialization of 'Movie' main.cpp line 14 C/C++ Problem
Isn't this correct, am I missing something? Thanks
When you do this
Movie("MovieTitle", "Director");
you are passing string literals, which collapse to const char*. But your constructor takes non-const references to char *:
Movie::Movie(char *&t, char *&d) { .... }
You cannot bind non-const references to something that is const. But in actual fact, it doesn't look like you need references at all. Just take the pointers by value, but make them point to somewhing const:
Movie::Movie(const char* t, const char* d)
This requires that you change title and director to const char*, which makes sense if you want to make them point to string literals.
But note that the design relies on the caller passing string literals, or passing pointers to objects that will outlive the given Movie instance. This can be made to work, but is quite fragile. The safer option would be for the Movie to "own" the data, which can easily be done by giving it std::string member variables.
As juanchopanza noted, the problem is that string literals get converted to type const char*, but your constructor only takes references to (non-const) char*, so it doesn't match.
A second point is that
Movie * movies = new Movie[movie_size];//creating array of class "Movie"
Movie *movieone=new Movie("MovieTitle", "Director");
movies[0]=movieone;
won't work. The first line creates an array of Movies (or tries to -- it won't work unless you have a default constructor), but the third line tries to set the first entry to a Movie*. Instead, you need to either a) create movies as an array holding pointers to Movies, or b) copy movieone by saying
movies[0] = *movieone;
Either way, you need to be very careful with regard to object lifetimes with this approach; it would be very easy to either leak memory on the one hand, or keep references to non-existent objects on the other.
A much better approach is to not (directly) use any dynamic memory allocation at all. You can use standard library facilities which hide it all for you, like this:
class Movie
{
public:
Movie(const std::string& title, const std::string& director)
: _title(title), _director(director) {}
private:
std::string _title;
std::string _director;
};
// later...
std::vector<Movie> movies;
movies.push_back(Movie("Jurassic Park", "Steven Speilberg"));
This is safer, easier to use, and no less efficient than your approach above.
Consider using std::string for store strings in class. For arguments pass better use const string& or const char*.
Movie *movieone=new Movie("MovieTitle", "Director");
Here you're passing const char*, but your constructor expects char*, so it doesn't match. Consider changing constructor to string or const char*
I need to store a list of various properties of an object. Property consists of a name and data, which can be of any datatype.
I know I can make a class "Property", and extend it with different PropertySubClasses which only differ with the datatype they are storing, but it does not feel right.
class Property
{
Property(std::string name);
virtual ~Property();
std::string m_name;
};
class PropertyBoolean : Property
{
PropertyBoolean(std::string name, bool data);
bool m_data;
};
class PropertyFloat : Property
{
PropertyFloat(std::string name, float data);
float m_data;
};
class PropertyVector : Property
{
PropertyVector(std::string name, std::vector<float> data);
std::vector<float> m_data;
};
Now I can store all kinds of properties in a
std::vector<Property*>
and to get the data, I can cast the object to the subclass. Or I can make a pure virtual function to do something with the data inside the function without the need of casting.
Anyways, this does not feel right to create these different kind of subclasses which only differ by the data type they are storing. Is there any other convenient way to achieve similar behavior?
I do not have access to Boost.
C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.
class Property
{
public:
Property(const std::string& name) //note: we don't lightly copy strings in C++
: m_name(name) {}
virtual ~Property() {}
private:
std::string m_name;
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const std::string& name, const T& data)
: Property(name), m_data(data);
private:
T m_data;
};
typedef std::vector< std::shared_ptr<Property> > property_list_type;
Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:
void f()
{
std::vector<Property*> my_property_list;
for(unsigned int u=0; u<10; ++u)
my_property_list.push_back(new Property(u));
use_property_list(my_property_list);
for(std::vector<Property*>::iterator it=my_property_list.begin();
it!=my_property_list.end(); ++it)
delete *it;
}
That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.
The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".
In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.
Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.
A lower-level way is to use a union
class Property
union {
int int_data;
bool bool_data;
std::cstring* string_data;
};
enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;
// ... more smarts ...
};
Dunno why your other solution doesn't feel right, so I don't know if this way would feel better to you.
EDIT: Some more code to give an example of usage.
Property car = collection_of_properties.head();
if (car.data_type == Property::INT_PROP) {
printf("The integer property is %d\n", car.int_data);
} // etc.
I'd probably put that sort of logic into a method of the class where possible. You'd also have members such as this constructor to keep the data and type field in sync:
Property::Property(bool value) {
bool_data = value;
data_type = BOOL_PROP;
}
I suggest boost::variant or boost::any. [Related question]
Write a template class Property<T> that derives from Property with a data member of type T
Another possible solution is to write a intermediate class managing the pointers to Property classes:
class Bla {
private:
Property* mp
public:
explicit Bla(Property* p) : mp(p) { }
~Bla() { delete p; }
// The standard copy constructor
// and assignment operator
// aren't sufficient in this case:
// They would only copy the
// pointer mp (shallow copy)
Bla(const Bla* b) : mp(b.mp->clone()) { }
Bla& operator = (Bla b) { // copy'n'swap trick
swap(b);
return *this;
}
void swap(Bla& b) {
using std::swap; // #include <algorithm>
swap(mp, b.mp);
}
Property* operator -> () const {
return mp;
}
Property& operator * () const {
return *mp;
}
};
You have to add a virtual clone method to your classes returning a pointer to a newly created copy of itself:
class StringProperty : public Property {
// ...
public:
// ...
virtual Property* clone() { return new StringProperty(*this); }
// ...
};
Then you'll be able to do this:
std::vector<Bla> v;
v.push_back(Bla(new StringProperty("Name", "Jon Doe")));
// ...
std::vector<Bla>::const_iterator i = v.begin();
(*i)->some_virtual_method();
Leaving the scope of v means that all Blas will be destroyed freeing automatically the pointers they're holding. Due to its overloaded dereferencing and indirection operator the class Bla behaves like an ordinary pointer. In the last line *i returns a reference to a Bla object and using -> means the same as if it was a pointer to a Property object.
A possible drawback of this approach is that you always get a heap operation (a new and a delete) if the intermediate objects must be copied around. This happens for example if you exceed the vector's capacity and all intermediate objects must be copied to a new piece of memory.
In the new standard (i.e. c++0x) you'll be able to use the unique_ptr template: It
can be used inside the standard containers (in contrast to the auto_ptr which must not be used in the standard containers),
offers the usually faster move semantics (it can easily passed around) and
takes care over the held pointers (it frees them automatically).
I see that there are lots of shots at trying to solve your problem by now, but I have a feeling that you're looking in the wrong end - why do you actually want to do this in the first place? Is there some interesting functionality in the base class that you have omitted to specify?
The fact that you'd be forced to switch on a property type id to do what you want with a specific instance is a code smell, especially when the subclasses have absolutely nothing in common via the base class other than a name (which is the type id in this case).
Starting with C++ 17 we have something called as std::variant and std::any.
std::variant
An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value.
std::any
The class any describes a type-safe container for single values of any copy constructible type.
An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, and this is referred to as the state of the class any object. The stored instance is called the contained object. Two states are equivalent if they are either both empty or if both are not empty and if the contained objects are equivalent.
The non-member any_cast functions provide type-safe access to the contained object.
You can probably do this with the Boost library, or you could create a class with a type code and a void pointer to the data, but it would mean giving up some of the type safety of C++. In other words, if you have a property "foo", whose value is an integer, and give it a string value instead, the compiler will not find the error for you.
I would recommend revisiting your design, and re-evaluating whether or not you really need so much flexibility. Do you really need to be able to handle properties of any type? If you can narrow it down to just a few types, you may be able to come up with a solution using inheritance or templates, without having to "fight the language".
So I decided to dwelve a bit within the pesty C++.
When I call the delete function on a pointer to a simple class that I created I'm greeted by a Debug Assertion Failure -Expression:_BLOCK_TYPE_IS_VALID(pHead->nBlockUse). I assume this is because I've handled the string manipulation wrong and thus causing memory corruption.
I created a basic class, [I]animal[/I], that has a string defined that can be set through a function.
// name
char * ptrName;
animal::animal(char * name)
{
this->SetName(name);
};
animal::~animal()
{
delete [] ptrName;
}
void animal::SetName(char * name)
{
ptrName = name;
};
When using the above class as shown below the error occurs. I've tried both delete ptrName and delete [] ptrName but to no avail.
animal * cat = new animal("Optimus Prime");
delete cat;
What am I missing?
The string "Optimus Prime" was not dynamically allocated, and thus it is not correct to call delete on it.
The problem comes from deleting a pointer that you don't own. You haven't allocated the string, so you must not delete it. The C string you are using is allocated statically by the compiler.
The problem is that in the setName function you are merely assigning the name to ptrName. In the example, the name is a const char string pointer which you can't delete (it is not allocated on the heap). To avoid this error, you can either use a std::string in the class or allocate a new char arry in the constructor of the animal class and assign the pointer to it. Then, in the destructor you can delete the array.
So I decided to dwelve a bit within the pesty C++.
Then do yourself a favor and use C++ right. That would be to use std::string:
// name
std::string name_;
animal::animal(const std::string& name)
: name_(name)
{
}
//animal::~animal() // not needed any longer
//note: copying also automatically taken care of by std::string
//animal(const animal&)
//animal& operator=(const animal&)
void animal::SetName(const std::string& name)
{
name_ = name;
}
Have a look at The Definitive C++ Book Guide and List. I'd recommend Accelerated C++. It comes with a steep learning curve, but since you already know a bit of C++, it's the 250 pages that might set you on the right track.
As a rule of thumb: Whenever you release a resource (memory or other), and it's not in the destructor of a class whose solely purpose is to manage this one resource, something is wrong with your design. Personally, I become suspicious whenever I feel the need to write a destructor, copy constructor, or assignment operator.
Who has ownership of your string?
For example, when you construct your new animal, you're passing in a string literal - that's not yours to free.
You should consider avoiding char* and just using std::string instead.
If you have to use char*, think about ownership. For example, one option is for you to take a copy of the string (using strdup) and own that. This way you can't be stuck with strange bugs like this
char* szFoo = strdup("my string");
{
animal a(szFoo);
}
// At this point szFoo has been deleted by the destructor of a
// and bad things will start to happen here.
printf("The value of my string %s",szFoo);