The role of the new
operator is to allocate a region of memory (heap, not the execution stack) to the data, and invoke in each cell the constructor for that data type. This means that every time you run the new
operator it takes up more memory and, as memory has a limit, you can not call new
at will without using delete
before memory is missing for another new
.
Programs that need to do a lot of memory allocations (such as symbolic math programs, web servers, and so on) need to manage memory well, so they eliminate unnecessary data if that region of memory is needed for something later. Common programs that need to allocate a lot of data may also have problems like this, but it is less common.
Typically, in C ++ the data allocated in a scope is deallocated in it, which is a good programming practice based on variable life-time control and guarantees the deallocation of data no longer needed. In cases of data that need to persist in scopes above, the data is already built into or copied to the original scope variables.
In order to facilitate this control of the life time, it is usually used to construct structures and class objects in order to allocate the data whenever the objects are created and also the destructor to delete them, practically automating the control of the the lifetime of the data allocated in the heap without having to remember to use new
and delete
at the right time.
With this, you could make a structure like this.
struct StringType {
private:
char *strChars ;
size_t strLen ;
void constroy( size_t len ){
strChars = new char[ (strLen=len)+1 ] ;
}
void constroyCopy( const StringType &string ){
constroy( string.StrLen ) ;
for( size_t index=0 ; index<=StrLen ; index++ ){
StrChars[index] = string.StrChars[index] ;
}
}
void destroy( void ){
delete strChars ;
}
public:
~StringType( void ){
destroy() ;
}
StringType( size_t maxLength ){
constroy(maxLength) ;
}
StringType( const StringType &string ){
constroyCopy(string) ;
}
resetString( size_t newMaxLength ){
destroy() ;
constroy(newMaxLength ) ;
}
resetString( const StringType &string ){
destroy() ;
constroyCopy(string) ;
}
size_t length( void ){
return strLen ;
}
const char* charPointer( void ){
return strChars ;
}
}
And then if you want the data to persist by copy you do a function that returns the structure, then it will be copied.
StringType char* enc( const char* Str ){
StringType _Str( strlen(Str) ) ;
for( size_t i=0 ; i<_Str.length() ; i++ ) _Str.charPointer[i] = Str[i]+4 ;
_Str.charPointer[len] = 'void enc( const char* Str , String *Str_out ){
Str_out.resetString( strlen(Str) ) ;
for( size_t i=0 ; i<Str_out.length() ; i++ ) Str_out.charPointer[i] = Str[i]+4 ;
Str_out.charPointer[len] = 'auto len = strlen(Str);
char* _Str = new char[len];
';
}
';
return _Str ;
}
But if you prefer better performance you can save the data directly into a destination structure by passing its address as an argument.
_Str[len] = 'void enc( const char* Str , char* _Str_out ){
size_t len = strlen(Str) ;
for( size_t i=0 ; i<len ; i++ ) _Str_out[i] = Str[i]+4 ;
_Str_out[len] = 'void enc( const char* Str , char* _Str_out ){
size_t i ;
for( i=0 ; Str[i]!='struct StringType {
private:
char *strChars ;
size_t strLen ;
void constroy( size_t len ){
strChars = new char[ (strLen=len)+1 ] ;
}
void constroyCopy( const StringType &string ){
constroy( string.StrLen ) ;
for( size_t index=0 ; index<=StrLen ; index++ ){
StrChars[index] = string.StrChars[index] ;
}
}
void destroy( void ){
delete strChars ;
}
public:
~StringType( void ){
destroy() ;
}
StringType( size_t maxLength ){
constroy(maxLength) ;
}
StringType( const StringType &string ){
constroyCopy(string) ;
}
resetString( size_t newMaxLength ){
destroy() ;
constroy(newMaxLength ) ;
}
resetString( const StringType &string ){
destroy() ;
constroyCopy(string) ;
}
size_t length( void ){
return strLen ;
}
const char* charPointer( void ){
return strChars ;
}
}
' ; i++ ) _Str_out[i] = Str[i]+4 ;
_Str_out[i] = 'StringType char* enc( const char* Str ){
StringType _Str( strlen(Str) ) ;
for( size_t i=0 ; i<_Str.length() ; i++ ) _Str.charPointer[i] = Str[i]+4 ;
_Str.charPointer[len] = 'void enc( const char* Str , String *Str_out ){
Str_out.resetString( strlen(Str) ) ;
for( size_t i=0 ; i<Str_out.length() ; i++ ) Str_out.charPointer[i] = Str[i]+4 ;
Str_out.charPointer[len] = 'auto len = strlen(Str);
char* _Str = new char[len];
';
}
';
return _Str ;
}
' ;
}
';
}
';
Note: In this snippet of your code
_Str[len] = 'void enc( const char* Str , char* _Str_out ){
size_t len = strlen(Str) ;
for( size_t i=0 ; i<len ; i++ ) _Str_out[i] = Str[i]+4 ;
_Str_out[len] = 'void enc( const char* Str , char* _Str_out ){
size_t i ;
for( i=0 ; Str[i]!='%pre%' ; i++ ) _Str_out[i] = Str[i]+4 ;
_Str_out[i] = '%pre%' ;
}
';
}
';
You have allocated cells with 0, 1, ..., len-1
and in this
%pre%
You saved in the index cell len
, which does not exist. To avoid possible errors (such as having something else allocated in that memory region that will be lost), allocate one more cell. In the codes I've made, I have already automated this by allocating% of cells% in constructing the string structure.
Any questions?
Edit: There is a workaround that preserves the way you program, does not require a deployed structure, and should perform better. All you have to do is add a parameter that is an array of target characters so that you write the solution in it instead of allocating and returning an array of characters. With this, you have all the control of creating and removing the data from outside the function, and may involve scopes or other criteria that you consider more appropriate.
%pre%
One more thing, you can do this without having to call the function that counts the number of characters in the string, thus improving performance.
%pre%