I have class Citizen { string name,address ... } and then I have class TaxRegister.
class TaxRegister
{
public:
bool Add_citizen ( const string& name, const string& addr );
private:
static const int m_Size=1000;
int m_Index,m_IncrementedSize;
Citizen * m_People[m_Size];
};
bool TaxRegister::Add_citizen( const string& name, const string& addr )
{
....
m_People[m_Index++] = new Citizen( name,addr );
}
The problem is, when I have to add more then 1000 people into my array;
I tried to do this:
Citizen *tmp[m_IncrementedSize*=2];
for (int i=0; i < m_Index; i++ )
tmp[i]=m_People[i];
delete [] m_People;
m_People=tmp;
m_IncrementedSize*=2;
But the compilator gives me this:
incompatible types in assignment of ‘CCitizen* [(((sizetype)) + 1)]’ to ‘CCitizen* [1000]’
Does anybody know how to fix it ? Thank you.
Use std::vector<Citizen> instead of an array and the problem will likely disappear by itself. A standard container like std::vector manages all memory automatically for you. You will end up with no new and delete[] at all in your code.
Just to give you an idea, this is what your Add_citizen function would then look like:
void TaxRegister::Add_citizen( const string& name, const string& addr )
{
m_People.push_back(Citizen(name, addr));
}
You are already using std::string instead of char const *. That's good. Using std::vector instead of arrays is exactly the same improvement.
If you want to stick to arrays, just make sure that the size parameter in the array declaration is actually a constant, rather than a variable. And then allocate a new array.
Related
When I initialize the constructor with the given data type of the parameter, I find that it goes wrong with the explaination that " const char* values cannot be assigned to char* entities".
class TString
{
private:
char* m_pData;
int m_nLength;
public:
TString();
TString(const char* pStr);
······
}
TString::TString(const char* pStr) {
this->m_pData = pStr;
}
What should I do to solve this problem? If possible, give me a right example.
Thanks in advance and apolpgize for my ignorance.
Const char * generally are prefined static compiled strings that cannot be changed because they are locked in the source code, or they come from some immutable source. This is in part, why they are marked const to prevent people from trying to change them.
The easiest solution to this problem is to take the const char * and make a copy of it on the heap, then it is no longer constant.
For example:
#include <string.h> // for strdup
...
TString::TString(const char* pStr) {
m_pData = strdup(pStr); // this will malloc and copy the string accepting const char * as input.
}
One thing you will need to consider, the m_pData is now on the heap, so in the destructor, you will want to free this data otherwise you will have a memory leak.
TString::~TString(){
free(m_pData);
}
You will also want in the TString() constructor to set the m_pData=NULL too.
This will work with strings, but if it's binary data i.e. no terminator allocate the data using malloc and use a memcpy, like:
m_pData=(char *)malloc(m_nlength*sizeof(char));
memcpy(m_pData,pStr,m_nlength);
Or some such.
I can't find the answer anywhere.
I wrote this class:
class Message {
private:
char senderName[32];
char* namesOfRecipients[];
int numOfContacts;
char subject[129];
char body[10001];
};
And I'm trying to write a constructor with default arguments like this:
Message(char senderName[32]="EVA",
char* Recipents[]={"glados","edi"},
int numOfRec=3,
char subject[129]="None",
char content[10001]="None");
However, it won't accept the recipients default argument no matter how I write it.
Is it even possible to pass a 2D array as a default argument for a constructor?
Sooo many pointers and arrays... if It is C++ why bother? Just write:
class Message {
private:
std::string senderName;
std::vector<std::string> namesOfRecipients;
int numOfContacts;
std::string subject;
std::string body;
};
And:
Message("EVA", {"glados","edi"}, 3, "None", "None");
And everbody is happy...
As Paul mentioned, you should change the declaration of namesOfRecipients to
char **namesOfRecipients;
Then you can have a private const static array of default names in the class and initialize namesOfRecipients with a pointer to its first element. The code is below.
Edit: It's important to understand what the data semantics are here, for example compared to Jarod's solution. The default ctor stores the address of an array of constant pointers to constant character strings. It's not at all possible to copy different characters into a name or to let one of the pointers in the array point to a new name, or to append a name. The only legal thing here is to replace the value of namesOfRecipients with a pointer to a new array of pointers to char.
class Message {
private:
char senderName[32];
char** namesOfRecipients;
int numOfContacts;
char subject[129];
char body[10001];
static const char* defaultNames[];
public:
Message(const char senderName[32]="EVA",
const char** Recipents = defaultNames,
int numOfRec=3,
const char subject[129]="None",
const char content[10001]="None");
};
const char *Message::defaultNames[] = {"Jim", "Joe"};
You can do something like:
namespace
{
char (&defaultSenderName())[32]
{
static char s[32] = "EVA";
return s;
}
const char* (&defaultNamesOfRecipients())[2]
{
static const char* namesOfRecipients[2]={"glados", "edi"};
return namesOfRecipients;
}
}
class Message {
private:
char senderName[32];
const char* namesOfRecipients[2];
public:
Message(char (&senderName)[32] = defaultSenderName(),
const char* (&namesOfRecipients)[2] = defaultNamesOfRecipients())
{
std::copy(std::begin(senderName), std::end(senderName), std::begin(this->senderName));
std::copy(std::begin(namesOfRecipients), std::end(namesOfRecipients), std::begin(this->namesOfRecipients));
}
};
but using std::string/std::vector would be simpler.
Use a separate array of pointers (it's not a 2-D array, though it may look like it) as a default argument:
char* defaultRecipents[] = {"glados","edi"};
class Message {
public:
Message(char senderName[32]="EVA",
char* Recipents[]=defaultRecipents){}
};
Specifying the default array "inline" doesn't work because the compiler "thinks" about it in terms of std::initializer_list, which is only suitable in initialization, not in declaration. Sorry if this sounds vague; I don't have enough experience with this matter.
Note: you might want to use const to declare your strings, to make it clear to the compiler (and your future self) whether the class is or is not going to alter the strings:
const char* const defaultRecipents[] = {"glados","edi"};
class Message {
public:
Message(char senderName[32]="EVA",
const char* const Recipents[]=defaultRecipents){}
};
Here it says const twice to declare that it's not going to:
Change the array elements (e.g. replace one array element, which is a string, by another string or nullptr); and
Change the contents of the strings (e.g. cut a string in the middle, or edit it)
I'm trying to re-learn C++ and was wondering if anyone could help me out here. I'm trying to implement my own String class to see if I can remember things, but I'm stuck on the constructor.
I have my header file and want to have a constructor as so:
Header File (MyFiles\String.h):
#ifndef STRING_
#define STRING_
using namespace std;
#include <iostream>
class String
{
private:
static const unsigned int MAX = 32; // Capacity of string
char Mem[MAX]; // Memory to hold characters in string
unsigned Len; // Number of characters in string
public:
// Construct empty string
//
String()
{
Len = 0;
}
// Reset string to empty
//
void reset()
{
Len = 0;
}
// Return status information
//
bool empty() const
{
return Len == 0;
}
unsigned length() const
{
return Len;
}
// Return reference to element I
//
char& operator[]( unsigned I )
{
return Mem[I];
}
// Return constant reference to element I
//
const char& operator[]( unsigned I ) const
{
return Mem[I];
}
// Construct string by copying existing string
//
String( const String& );
// Construct string by copying array of characters
//
String( const char [] );
// Copy string to the current string
//
String& operator=( const String& );
// Append string to the current string
//
String& operator+=( const String& );
};
// Compare two strings
//
bool operator==( const String&, const String& );
bool operator!=( const String&, const String& );
// Put a string into an output stream
//
ostream& operator<<( ostream&, const String& );
#endif
The bit I'm stuck on is this:
String::String(const String& str)
{
//what goes here?
}
Thanks!
Well, since it's a learning exercise.
I think you want to copy the contents of the other string here since this is a copy constructor. So you will want to copy across all the member variables. In your case
the copy constructor is not necessary because you've got a static array. If you had
dynamic memory (i.e. used new to allocate pointer to Mem) then you'd need this. However,
to show you how it's done, here you go.
String::String(const String& str)
{
//what goes here?
assert(str.Len < MAX); // Hope this doesn't happen.
memcpy(Mem, str.Mem, str.Len);
Len = str.Len;
}
You need to copy the data from str to this. The length is easy:
Len = str.Len; // or, equiv. this->Len= str.Len
The data is a little harder. You might use strcpy or memcpy, or even a for loop.
memcpy(Mem, str.Mem, sizeof Mem);
Good luck!
I concur with Kornel Kisielewicz: the fewer hand-rolled String classes, the better. But you're only doing this to learn, so fair enough :-). Anyway: your copy constructor needs to copy over the length and the contents of the Mem array, and that's it.
(If you were doing this to make something useful rather than as a learning exercise, I'd add: a string class with a fixed maximum string length -- especially one as small as 32 characters -- is a very bad idea indeed. But it's entirely reasonable if you don't feel like dealing with memory allocation and deallocation at the same time as you're trying to remember the even-more-basics...)
I am having difficulty writing my code in the way it should be written. This is my default constructor:
Address::Address() : m_city(NULL), m_street(NULL), m_buildingNumber(0), m_apartmentNumber(0)
{}
...and this is my other constructor:
Address::Address(const char* city, const char* street, const int buildingNumber,const int apartmentNumber) : m_city(NULL), m_street(NULL)
{
SetAddress(city,street,buildingNumber,apartmentNumber);
}
I have to initialize my city and street fields as they contain char * and my setter uses remove to set a new city for example. I would very much like to hear your opinion on how to write it in the right way without repeating code.
this is my SetAddress code :
bool Address::SetAddress(const char* city, const char* street, const int buildingNumber, const int apartmentNumber)
{
if (SetCity(city) == false || SetStreet(street) == false || SetBuildingNumber(buildingNumber) == false || SetApartmentNumber(apartmentNumber) == false)
return false;
return true;
}
and this is my SetCity:
bool Address::SetCity(const char* city)
{
if(city == NULL)
return false;
delete[] m_city;
m_city = new char[strlen(city)+1];
strcpy(m_city, city);
return true;
}
1 more question if i do change char* to string how can i check if string city doesnt equal to NULL as i know string does not have the "==" operator and string is an object and cannot be equal to null,
how can i check if the string i get is indeed legeal.
You should use std::string instead of C strings (const char*). Then you don't have to worry about having a "remove" function because std::string will manage the memory for you.
The only repeating code I see is the initializers. Since you should both be using initializers and cannot share initializers, some code redundancy is required here. I wouldn't worry about it.
When the new C++ comes out you'll be able to call the former constructor during initialization of the later. Until then, you'll just have to live with this minor smell.
You can combine the two ctors:
Address::Address(const char* city=NULL,
const char* street=NULL,
int buildingNumber=0,
int apartmentNumber=0)
: m_city(city),
m_street(street),
m_buildingNumber(buildingNumber),
m_apartmentNumber(apartmentNumber)
{}
[The top-level const on buildingNumber and apartmentNumber accomplished nothing and attempt to move implementation information into the interface, so I remove them.]
Of, if you really prefer:
Address::Address(const char* city=NULL,
const char* street=NULL,
int buildingNumber=0,
int apartmentNumber=0)
{
SetAddress(city,street,buildingNumber,apartmentNumber);
}
I generally prefer the former, but if SetAddress qualifies its inputs, it may be worthwhile. Of course, the suggestion to use std::string instead of pointers to char is a good one as well, but that's a more or less separate subject.
One other minor note: this does differ in one fundamental way from your original code. Your code required either 0 or 4 arguments to the ctor. This will accept anywhere from 0 to 4, arguments so a person could specify (for example) a city and street, but not a building number or apartment number. If it's really important to you that attempts at using 1, 2 or 3 arguments be rejected, this approach won't be useful to you. In this case, the extra flexibility looks like an improvement to me though -- for example, if somebody lives in a single-family dwelling, it's quite reasonable to omit an apartment number.
As answered by others (James McNellis' answer comes to mind), you should switch to std:string instead of char *.
Your problem is that repetition can't be avoided (both non default constructor and the setAddress method set the data), and having one calling the other could be less effective.
Now, the real problem, I guess, is that your code is doing a lot, which means that repetition of delicate code could be dangerous and buggy, thus your need to have one function call the other. This need can be remove by using the std::string, as it will remove the delicate code from your code altogether.
As it was not shown
Let's re-imagine your class:
class Address
{
public :
Address() ;
Address(const std::string & p_city
, const std::string & p_street
, int p_buildingNumber
, int p_apartmentNumber) ;
// Etc.
private :
std::string m_city ;
std::string m_street ;
int m_buildingNumber ;
int m_apartmentNumber ;
} ;
Using the std::string instead of the const char * will make the std::string object responsible for handling the resource (the string itself).
For example, you'll see I wrote no destructor in the class above. This is not an error, as without a destructor, the compiler will generate its own default one, which will handle the destructor of each member variable as needed. The remove you use for resource disposal (freeing the unused char *) is useless, too, so it won't be written. This means a lot of delicate code that won't be written, and thus, won't produce bugs.
And it simplifies greatly the implementation of the constructors, or even the setAddress method :
Address::Address()
// std::string are initialized by default to an empty string ""
// so no need to mention them in the initializer list
: m_buildingNumber(0)
, m_apartmentNumber(0)
{
}
Address::Address(const std::string & p_city
, const std::string & p_street
, int p_buildingNumber
, int p_apartmentNumber)
: m_city(p_city)
, m_street(p_street)
, m_buildingNumber(p_buildingNumber)
, m_apartmentNumber(p_apartmentNumber)
{
}
void Address::setAddress(const std::string & p_city
, const std::string & p_street
, int p_buildingNumber
, int p_apartmentNumber)
{
m_city = p_city ;
m_street = p_street ;
m_buildingNumber = p_buildingNumber ;
m_apartmentNumber = p_apartmentNumber ;
}
Still, there is repetition in this code, and indeed, we'll have to wait C++0x to have less repetition. But at least, the repetition is trivial, and easy to follow: No dangerous and delicate code, everything is simple to write and read. Which makes your code more robust than the char * version.
Your code looks good - it might be worthy to see the contents of SetAddress. I would highly recommend using std::string over char *s, if city and street aren't hard-coded into the program, which I doubt. You'll find std::string will save you headaches with memory-management and bugs, and will generally make dealing with strings much easier.
I might rewrite the setAddress() method as follows:
bool Address::setAddress(const char* city, const char* street, const int buildingNumber, const int apartmentNumber)
{
return (setCity(city)
&& setStreet(street)
&& setBuildingNumber(buildingNumber)
&& setApartmentNumber(apartmentNumber))
}
which will achieve the same short-circuiting and returning semantics, with a bit less code.
If you must use char * rather than std::string you need to manage the memory for the strings yourself. This includes copy on write when sharing the text or complete copy of the text.
Here is an example:
class Address
{
public:
Address(); // Empty constructor.
Address(const char * city,
const char * street,
const char * apt); // Full constructor.
Address(const Address& addr); // Copy constructor
virtual ~Address(); // Destructor
void set_city(const char * new_city);
void set_street(const char * new_street);
void set_apartment(const char * new_apartment);
private:
const char * m_city;
const char * m_street;
const char * m_apt;
};
Address::Address()
: m_city(0), m_street(0), m_apt(0)
{ ; }
Address::Address(const char * city,
const char * street,
const char * apt)
: m_city(0), m_street(0), m_apt(0)
{
set_city(city);
set_street(street);
set_apt(apt);
}
Address::Address(const Address& addr)
: m_city(0), m_street(0), m_apt(0)
{
set_city(addr.city);
set_street(addr.street);
set_apt(addr.apt);
}
Address::~Address()
{
delete [] m_city;
delete [] m_street;
delete [] m_apt;
}
void Address::set_city(const char * new_city)
{
delete [] m_city;
m_city = NULL;
if (new_city)
{
const size_t length = strlen(new_city);
m_city = new char [length + 1]; // +1 for the '\0' terminator.
strcpy(m_city, new_city);
m_city[length] = '\0';
}
return;
}
void Address::set_street(const char * new_street)
{
delete [] m_street;
m_street = NULL;
if (new_street)
{
const size_t length = strlen(new_street);
m_street = new char [length + 1]; // +1 for the '\0' terminator.
strcpy(m_street, new_street);
m_street[length] = '\0';
}
return;
}
void Address::set_apt(const char * new_apt)
{
delete [] m_apt;
m_apt = NULL;
if (new_apt)
{
const size_t length = strlen(new_apt);
m_apt = new char [length + 1]; // +1 for the '\0' terminator.
strcpy(m_apt, new_apt);
m_apt[length] = '\0';
}
return;
}
In the above example, the Address instance holds copies of the given text. This prevents problems when another entity points to the same text, and modifies the text. Another common issue is when the other entity deletes the memory area. The instance still holds the pointer, but the target area is invalid.
These issues are avoided by using the std::string class. The code is much smaller and easier to maintain. Look at the above code versus some of the other answers using std::string.
I'm an intermittent programmer and seem to have forgotten a lot of basics recently.
I've created a class SimPars to hold several two-dimensional arrays; the one shown below is demPMFs. I'm going to pass a pointer to an instance of SimPars to other classes, and I want these classes to be able to read the arrays using SimPars accessor functions. Speed and memory are important.
I know life is often simpler with vectors, but in this case, I'd really like to stick to arrays.
How do I write the accessor functions for the arrays? If I'm interested in the nth array index, how would I access it using the returned pointer? (Should I write a separate accessor function for a particular index of the array?) What's below is certainly wrong.
// SimPars.h
#ifndef SIMPARS_H
#define SIMPARS_H
#include "Parameters.h" // includes array size information
class SimPars {
public:
SimPars( void );
~SimPars( void );
const double [][ INIT_NUM_AGE_CATS ] get_demPMFs() const;
private:
double demPMFs[ NUM_SOCIODEM_FILES ][ INIT_NUM_AGE_CATS ];
};
#endif
// SimPars.cpp
SimPars::SimPars() {
demPMFs[ NUM_SOCIODEM_FILES ][ INIT_NUM_AGE_CATS ];
// ...code snipped--demPMFs gets initialized...
}
//...destructor snipped
const double [][ INIT_NUM_AGE_CATS ] SimPars::get_demPMFs( void ) const {
return demPMFs;
}
I would greatly appreciate some kind of explanation with proposed solutions.
Basically, you have three options: return the entire array by reference, return the first row by pointer, or return the entire array by pointer. Here is the implementation:
typedef double array_row[INIT_NUM_AGE_CATS];
typedef array_row array_t[NUM_SOCIODEM_FILES];
array_t demPMFs;
const array_t& return_array_by_reference() const
{
return demPMFs;
}
const array_row* return_first_row_by_pointer() const
{
return demPMFs;
}
const array_t* return_array_by_pointer() const
{
return &demPMFs;
}
And here are the use cases:
SimPars foo;
double a = foo.return_array_by_reference()[0][0];
double b = foo.return_first_row_by_pointer()[0][0];
double c = (*foo.return_array_by_pointer())[0][0];
How would I return just the nth row of the array?
Again, you have three choices:
const array_row& return_nth_row_by_reference(size_t row) const
{
return demPMFs[row];
}
const double* return_first_element_of_nth_row_by_pointer(size_t row) const
{
return demPMFs[row];
}
const array_row* return_nth_row_by_pointer(size_t row) const
{
return demPMFs + row;
}
const double (* get_demPMFs() const)[INIT_NUM_AGE_CATS];
Or, use typedef (but that doesn't seems cleaner...).
class SimPars {
typedef const double (*ConstDemPMFType)[INIT_NUM_AGE_CATS];
double demPMFs[NUM_SOCIODEM_FILES][INIT_NUM_AGE_CATS];
public:
ConstDemPMFType get_demPMFs() const;
};
Note that you can't return an array (g++ refuses the compile). But an array of array can be decayed to a pointer to array, so the latter is returned.
Logically speaking there is this question with a data member. Should users be allowed to modify it or not. If you want to give another class full access to the member, you don't necessarily need getter/setter, especially if you are the only user. You can just make the member public.
If your class would be better off controlling how users access the member, then you could use a getter only to enforce read only access. The simplest way to do this if you don't want to get all confused about the 2-dimensional arrays is to just have an inline function fetching the element for the user class:
const double& getElem( int x, int y ) const { return demPMF[x][y] }
It makes sense to do bounds checking here, but considering that you insist on using arrays, and if your profiler proves that you can't afford it, this function would just allow access to your array.
If you want further elaboration, post a comment...