misunderstanding about the operator definition c++ - c++

I'm trying to understand why the operator (<) defined for this class insn't executed when called:
//File A.h (simplified class)
#ifndef __A__H
#define __A__H
#include <string>
#include <cstdlib>
#include <iostream>
using namespace std;
class A {
private:
string _str;
int _number;
public:
A( string str="", int age=0): _str(str), _number(number){} //inline
int operator < (const A &a1 ) const
{
cout<<"Call of new operator <"<<endl;
if ( _str == a1._str )
return _number < a1._number;
return _str < a1._str; //here use of (<) associated to string
}
};
#endif
int main()
{
A *obj1= new A("z",10);
A *obj2= new A("b",0);
int res=obj1<obj2; //res is equal to 1. There's no message
// call of new operator"
return 0;
}
What I've learned is that the redefinition of the operator permits its call. Any help ? thank you

obj1 and obj2 are A* not A so all you are doing is comparing pointer addresses. If you want to use A::operator< then you need to dereference your pointers
*obj1 < *obj2
Also why would you have your operator< return an int? It should return a bool.

You are comparing pointers to A, not instances of A in this statement
int res=obj1<obj2;
You should compare like this:
int res=*obj1< *obj2;
You also have to delete the memory you have allocated at the end of the program.
delete obj1;
delete obj2;

Related

C++ text argument to constructor

cont = cont;
I don't know how to convert cont to cont type pointer.
If I do like this : this->cont = (char*)cont;
In deconstructor I have exception error.
So is it good to convert const char to char* or I need to do better (but how?) ?
And I have to have dynamic allocate.
#include "pch.h"
#include <iostream>
#include <stdio.h>
using namespace std;
class Matrix {
private:
int x;
char *cont;
public:
Matrix(){
cout << "aa";
}
Matrix(const char *cont) {
this->cont = cont;
}
~Matrix() {
delete cont;
}
};
int main()
{
Matrix("__TEXT__");
system("pause");
return 0;
}
this->cont = cont;
Is "wrong", as in, it doesn't actually copy the data; that's also why delete in your destructor if failing. Your answer mentions "I have to have dynamic allocate.", so I presume that's what you actually wanted. In this case, simply use std::string:
class Matrix {
private:
int x;
std::string cont; // <--- changed type
public:
Matrix(){
cout << "aa";
}
Matrix(const char *cont)
: cont(cont) { // <--- this actually copies
}
};
first you have to allocate space for a pointer to char using new .
And in the destructor deallocate that space " delete [] cont " instead of "delete cont" .
but it will be a good choice to use std::string instead of char []

How to swap array using pointer when array is a data member of a class

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.

copy object pointer into dynamic object array

I am working with a class I created that has a function addClass which allow the user to add A an Instance of Class to a dynamically allocated array.
Here is the code of the class and a simple test:
Class.h Listing
#ifndef CLASS_H
#define CLASS_H
#include<iostream>
class Class {
public:
Class(std::string text);
Class(const Class& orig);
virtual ~Class();
Class(std::string text, Class * name, int size);
std::string toString();
void addClass(Class * name, int size = 1);
Class getClass(int index);
private:
Class * classArray;
std::string value;
int size;
};
#endif /* CLASS_H */
Class.c Listing
#include "Class.h"
#include <cstdlib>
Class::Class(std::string text) {
classArray = NULL;
value = text;
size = 0;
}
Class::Class(const Class& orig) {/*...*/}
Class::~Class() {}
Class::Class(std::string text, Class * name, int size){
value = text;
this->size = size;
if(size == 1)
classArray = name;
else{
int i;
classArray = (Class*)malloc(size*sizeof(Class));
for(i = 0; i < size; i++){
classArray[i] = name[i];
}
}
}
std::string Class::toString(){
return value;
}
void Class::addClass(Class * name, int size){
int i;
Class * tmp = (Class*)malloc((this->size+size)*sizeof(Class));
for(i = 0; i < this->size-1; i++){
tmp[i] = classArray[i];
}
if(size == 1)
tmp[size-1] = name[0];//assignement method is the problem!!!??
else{
for(i = this->size; i < this->size+size-1; i++){
tmp[i] = name[i];
}
}
this->size += size;
free(classArray);
classArray = tmp;
}
Class Class::getClass(int index){
return classArray[index];
}
test.c Listing
#include<iostream>
#include "Class.h"
using namespace std;
int main(int argc, char** argv) {
Class * objectA = new Class("objectA");
Class * objectB = new Class("objectB");
cout << objectA->toString() << endl;
objectA->addClass(objectB);
//never gets here :'(
cout << objectA->toString() << endl;
return 0;
}
The problem is the test never gets past the objectA->addClass(objectB) instruction. I tried to debug and what I found was that the problem comes from the assignement instruction of the addClass() method. I also tried memcpy it didn't work. Does anyone have a solution for this please. Thanks.
Don't use malloc on C++ objects, use new and new[] and delete and delete[]. The problem with malloc in C++ is that it doesn't call the constructors for your objects, and free doesn't call the destructors. new, new[], delete and delete[] do. You get a crash because you are assigning to unconstructed objects and you get that because you didn't use new.
Not saying that's the only problem with your code, but it's the obvious one.
A basic solution is to prefer new and delete over malloc and free. A much better solution is to use a standard container such as std::vector to hold the elements at Class::addClass(). Let the computer take care of all that memory management; you will be saving a lot of development and debugging time.
Note that in your code you defined a custom copy constructor Class(const Class&) for your class, but you seem not having defined a copy assignment operator Class& operator=(const Class&). Note that in your code you use copy assignment (operator=) to make copies of your class, but you don't have a proper implementation of it.
Moreover, in C++ you should prefer using new[]/delete[] to C's malloc()/free(), and even better just use std::vector container for arrays.
You can also have a std::vector< SomeSmartPointer > (e.g. std::vector<std::shared_ptr<SomeClass>>, or std::vector<std::unique_ptr<SomeClass>>). In general, consider std::vector of some smart pointer, but don't use a std::vector of owning raw pointers (std::vector<SomeClass*>).

Using standard library in C++, copy algorithm

I am trying to learn the standard library in C++ and I'm trying to run my code, but I can't succeed. What have I forgotten and what do I need to add in my class "Class" to make the program run as it should?
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <iterator>
using namespace std;
class Class {
public:
Class (int ii, double dd ) : ival(ii) { dval = new double; *dval = dd; }
~Class() { delete dval; }
private:
int ival;
double *dval;
};
int main()
{
vector<Class> vec;
list<Class> list;
vec.push_back( Class(1, 2.2) );
vec.push_back( Class(2, 4.3) );
vec.push_back( Class(3, 5.7) );
ostream_iterator<const Class> classout(cout,"\n");
copy( vec.begin(), vec.end(), classout );
}
I'm basically trying to understand and use the copy-algorithm:
template
OutputIterator copy ( InputIterator first, InputIterator last,
OutputIterator result )
{
while (first!=last) *result++ = *first++;
return result;
}
std::ostream_iterator uses the insertion operator << to insert objects into the output stream. You must provide such an operator. An example implementation using a member function:
class Class {
public:
Class (int ii, double dd ) : ival(ii) { dval = new double; *dval = dd; }
~Class() { delete dval; }
void print(std::ostream &stream) const {
stream << ival << ' ' << *dval;
}
private:
int ival;
double *dval;
};
std::ostream& operator<< (std::ostream &stream, const Class &arg) {
arg.print(stream);
return stream;
}
As an alternative, you could also implement it by making it a friend and not creating a member function.
Your code has several problem. The first, which should lead to a compile error is, that your class doesn't declare a << operator for streamout, meaning that it can't be printed to a stream using a ostream_iterator. To fix that, you need to add such an operator to your class, e.g.:
class Class {
public:
Class (int ii, double dd ) : ival(ii) { dval = new double; *dval = dd; }
~Class() { delete dval; }
friend std::ostream& operator<<(std::ostream& os, const Class& c)
{
return os<<c.ival<<": "<<*c.dval;//or whatever you want your output to look like
}
private:
int ival;
double *dval;
};
However your code still contains one serious problem: A violation of the rule of three (or five/whatever if you are on c++11). Your class declares a custom destructor, but neither a custom copy constructor nor a custom assignment operator. This means that when you copy an instance of your class (such as putting it into a vector, both objects will contain the same pointer, leading to a runtime error due to double free on the destruction of the second object. To fix that you either need to declare those operations yourself or (even better) don't do resource management yourself, but use smart pointers instead (c++11 std::unique_ptr or std::shared_ptr, std::tr1::shared_ptr or a pointer from boost for pree C++11 code).

Overloading operator in C++ and dereference

I am practicing overloading operators in C++ right now and I have a problem.
I created String class, it has just to fields one is char array other is length.
I have a String "Alice has a cat" and when I call
cout<<moj[2];
I would like to get 'i', but now I am getting moj + 16u adress of moj + 2 sizeof(String)
When I call
cout<<(*moj)[2];
it works as it shoud but I would like to dereference it in overloaded operator definition. I tried many things but I can't find solution. Please correct me.
char & operator[](int el) {return napis[el];}
const char & operator[](int el) const {return napis[el];}
AND the whole code, the important things are down the page. It's compiling and working.
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <cstring>
using namespace std;
class String{
public:
//THIS IS UNIMPORTANT------------------------------------------------------------------------------
char* napis;
int dlugosc;
String(char* napis){
this->napis = new char[20];
//this->napis = napis;
memcpy(this->napis,napis,12);
this->dlugosc = this->length();
}
String(const String& obiekt){
int wrt = obiekt.dlugosc*sizeof(char);
//cout<<"before memcpy"<<endl;
this->napis = new char[wrt];
memcpy(this->napis,obiekt.napis,wrt);
//cout<<"after memcpy"<<endl;
this->dlugosc = wrt/sizeof(char);
}
~String(){
delete[] this->napis;
}
int length(){
int i = 0;
while(napis[i] != '\0'){
i++;
}
return i;
}
void show(){
cout<<napis<<" dlugosc = "<<dlugosc<<endl;
}
//THIS IS IMPORTANT
char & operator[](int el) {return napis[el];}
const char & operator[](int el) const {return napis[el];}
};
int main()
{
String* moj = new String("Alice has a cat");
cout<<(*moj)[2]; // IT WORKS BUI
// cout<<moj[2]; //I WOULD LIKE TO USE THIS ONE
return 0;
}
String* moj = new String("Alice has a cat");
cout<<(*moj)[2]; // IT WORKS BUI
// cout<<moj[2]; //I WOULD LIKE TO USE THIS ONE
That can't be done, the subscript operator in the later case is applied to a pointer. It is only possible to overload operators when at least one of the arguments is of user defined type (or a reference to it, but not a pointer); in this particular case the arguments are String* and 2, both fundamental types.
What you may do is drop the pointer altogether, I don't see why you need it:
String moj("Alice has a cat");
// cout<<(*moj)[2]; <-- now this doesn't work
cout<<moj[2]; // <-- but this does
String * means a pointer to a String, if you want to do anything with the String itself you have to dereference it with *moj. What you can do instead is this:
String moj = String("Alice has a cat"); // note lack of * and new
cout << moj[2];
Also note that anything you allocate with new needs to be deleted after:
String *x = new String("foo");
// code
delete x;