What approach to development in C ++ is more convenient to maintain?

Current specifications:

String data in the form of wide or narrow character arrays records the functionality for a class that provides data statistics and modifies data.

The requirement is that it can be maintained for a long time.

So my first approach is to require raw char arrays to be split into strings earlier, and then just specify the template class:

template<class T> class MyString { private: T _data; public: MyString(T& input) { _data = input; }; size_t doSomeWork() { //assume T is of type basic_string<...> and use iterators }; }; //Use const char* data = "zyx"; string blahblah(data); MyString<string> abc(blahblah); abc.doSomeWork(); 

or static member functions:

 class StringTools { public: static size_t doWork(const char*) {} static size_t doWork(const wchar_t*) {} }; //used like so: const char* data = "hallo kitty"; cout << StringTools::doWork(data); 

or use a strategy template:

 class MyString { protected: MyStringBase(); public: virtual ~MyStringBase(); virtual size_t doWork() = 0; }; class MyStringCharArray : public MyString { protected: char* _data; public: MyStringCharArray(const char* input) : MyString() { } virtual size_t doWork() {...}; }; //so it would be used like so const char* blah = "blah"; MyString* str = new MyStringCharArray(blah); cout << str->doWork(); delete str; 

and then in the future, if for some god-forgotten reason I switch to BStr, then it will only be necessary for the first two lines of code to be changed in addition to the newly written derived class.

I think that if I write a wrapper class, as in 1 and 3, it will become a lot more difficult thing, and any encapsulation will be broken, since I must allow access to the base one.

but if I create a class with only static functions, then everything that it does mimics a namespace that would be better served by some non-member functions, different from each other, encapsulated under the namespace "stringtools". But then I will still spread the mess of massive character arrays throughout the application, and additional verification should be performed, etc., And the specification is explicitly set for the class.

So what will be the cleanest and most convenient approach?

Rgds

+4
source share
4 answers

A better approach is to do something like stl algorithms.

Have a process algorithm that only accepts the string char / wchart_t begin and end iterator. Thus, your algorithm will work without problems for all lines that may touch in memory.

+4
source

It seems to me that instead of a class, it seems to you that you should think about universal algorithms that work with absolutely normal string / wstring data. Depending on what you need regarding statistics / modification, you don’t even need to write real algorithms, but just functors that will be used (for example) std::accumulate .

If you need to work with something like BSTR, you need to provide an iterator interface for BSTR. Personally, however, even when I deal with COM, I usually work with regular strings almost all the time and convert to BSTR only immediately before transferring it to some kind of COM object. Similarly, on the return trip, as soon as I get BSTR, I convert it to a regular string and work with it in this form. In theory, it might be faster to leave things as BSTR if you work with COM quite a bit, but I have not yet seen a conversion to / from regular strings turn into something approaching a bottleneck.

+1
source

The problem is unproven, and you overestimate it.

What statistics will be collected? What changes will be made to the lines? How many lines will there be? Does performance matter?

Why not go with a simple solution: write all your statistics / line routines to work in UTF-8 (assuming this is the encoding for your char s). If you need to work with a UTF-16 string, convert it to UTF-8, call the routine that runs on it, and then convert the modified string back to UTF-16. KISS.

Edit:

There is one more consideration: Is your algorithm an agnostic encoding (i.e. it does not depend on string encoding), i.e. is the only variable "latitude" characters? If so, a boilerplate procedure that takes an iterator of beginning and end, as parapura suggests, may well be an option.

Based on your explanation, it sounds as if your algorithm is currently encoding an agnostic, but since you mention maintainability, you should consider whether this will also be true in the future.

0
source

Okay, so I took on board what you all said, and I separated the algorithms from the specification. Imitating STLs, algorithms work with iterators; while "MyClass" requests a specification, encapsulates domain knowledge.

What does this look like for you guys?

first run the algorithm:

 /* MyLib --------------- Methods: countOccurances() - given the iterator pairs for two either contiguous areas of memory or containers - counts the number of times the second (needle) occurs in the first (haystack) - returns the count replaceOccurances() - same as countOccurances except when a sequence has been matched it is replaced by the replacement needle which must be the same length */ template<class fwdIt> size_t countOccurances(fwdIt haystackFront, fwdIt haystackEnd, fwdIt needleFront, fwdIt needleEnd) { size_t lengthOfNeedle = std::distance(needleFront,needleEnd); size_t lengthOfHaystack = std::distance(haystackFront,haystackEnd); size_t count = 0; while(true) { //find the needle fwdIt tempIT1 = haystackFront, tempIT2 = needleFront; while(true) { if(tempIT2 == needleEnd) { haystackFront += lengthOfNeedle; lengthOfHaystack -= lengthOfNeedle; count++; break; } else if(*tempIT1 != *tempIT2) { break; } tempIT1++; tempIT2++; } if(lengthOfNeedle <= lengthOfHaystack) { ++haystackFront; --lengthOfHaystack; } else { break; } } return count; } template<class fwdIt> size_t replaceOccurances(fwdIt haystackFront, fwdIt haystackEnd, fwdIt needleFront, fwdIt needleEnd, fwdIt replacementFront, fwdIt replacementEnd) { //The needle and its replacement must be the same length, //this method cannot be reponsible for growing a container it doesn't own. if(std::distance(needleFront, needleEnd) != std::distance(replacementFront, replacementEnd)) throw exception("The needle and its replacement are not the same length"); size_t lengthOfNeedle = std::distance(needleFront,needleEnd); size_t lengthOfHaystack = std::distance(haystackFront,haystackEnd); size_t count = 0; while(true) { //find the needle fwdIt tempIT1 = haystackFront, tempIT2 = needleFront; while(true) { if(tempIT2 == needleEnd) { //replace the needle for(fwdIt tempIT3 = replacementFront; haystackFront != tempIT1, tempIT3 != replacementEnd; haystackFront++, tempIT3++) { *haystackFront = *tempIT3; } count++; break; } else if(*tempIT1 != *tempIT2) { break; } tempIT1++; tempIT2++; } if(lengthOfNeedle <= lengthOfHaystack) { ++haystackFront; --lengthOfHaystack; } else { break; } } return count; } 

and now myclass

 class MyClass { public: static size_t getMyCount(std::string& sInput); static size_t getMyCount(std::wstring& sInput); static size_t replaceMyWithMY(std::string& sInput); static size_t replaceMyWithMY(std::wstring& sInput); protected: static std::string _narrowNeedle; static std::wstring _wideNeedle; static std::string _narrowReplacementNeedle; static std::wstring _wideReplacementNeedle; template<class T> static size_t _PerformStringOperation(T& sInput, T& sNeedle, bool replace = false, T& sReplacementNeedle = T()) { try { if(replace) { return replaceOccurances( sInput.begin(), sInput.end(), sNeedle.begin(), sNeedle.end(), sReplacementNeedle.begin(), sReplacementNeedle.end()); } else { return countOccurances( sInput.begin(), sInput.end(), sNeedle.begin(), sNeedle.end()); } } catch(MYException& e) { clog << "MyClass::_PerformStringOperation() - could not perform operation" << endl; clog << e.what(); throw; } catch(exception& e) { clog << "MyClass::_PerformStringOperation() - Something more fundemental went wrong" << endl; clog << e.what(); throw; } } }; 

and accompanying CPP

 std::string MyClass::_narrowNeedle("My"); std::wstring MyClass::_wideNeedle = std::wstring(L"My"); std::string MyClass::_narrowReplacementNeedle = std::string("MY"); std::wstring MyClass::_wideReplacementNeedle = std::wstring(L"MY"); size_t MyClass::getNiCount(std::string& sInput) { try { return _PerformStringOperation(sInput,_narrowNeedle); } catch(...) { throw; } } size_t MyClass::getNiCount(std::wstring& sInput) { try { return _PerformStringOperation(sInput,_wideNeedle); } catch(...) { throw; } } size_t MyClass::replaceNiWith(std::string& sInput) { try { return _PerformStringOperation(sInput,_narrowNeedle,true,_narrowReplacementNeedle); } catch(...) { throw; } } size_t MyClass::replaceNiWith(std::wstring& sInput) { try { return _PerformStringOperation(sInput,_wideNeedle,true,_wideReplacementNeedle); } catch(...) { throw; } } 
0
source

All Articles