FaTony wrote:Define "normal RTTI". I have no problems with current RTTI.
Normal RTTI means reflection. It means that I can take the pointer to the object and get ALL information about structure of it's type and, also, can dynamically find and call methods of this object by name and argument types. C++'s RTTI is a fake.
FaTony wrote:There is zero need for "finally" precisely because of RAII. If your classes don't follow RAII then you are doing it wrong.
RAII is not a magic pillow. C++ provides many duplicate facilities (pointers and references, macroses and templates, classes and structures). Programming with RAII input/output and interaction between processes is like shooting into leg. Finally allows to do code smarter and more predictive than using huge amount of wrapping classes instead of one that internally uses 'finally' statements. С++ adepts get cranky on RAII and write huge amount of templated code there where they just could insert 'finally'. If C++ is so 'flexible' and 'powerful', why it does not provide such 'duplicate to RAII facility' like 'finally'? Also RAII is poor ideology because... C++'s destructors can not throw exceptions (no, they can but it's very dangerous)! So to properly free/destruct resource I still should call special destroying routine before issuing the destructor or write tons of code that allow to pass error from destrutor to the environment. So in this case all usage of RAII goes to epic fail because I spend a lot of time by writing code that I shouldn't write if I used 'finally'.
FaTony wrote:Combined? What? auto_ptr was deprecated in C++11. Now we have unique_ptr and shared_ptr. What do you mean by "pointer metaprogramming"?
So this thing I directly mean. Now instead of auto_ptr we should use two type of template wrappers: unique_ptr and shared_ptr. And they have additional overhead of data and restrictions (still relative to RAII!).
FaTony wrote:C doesn't have it too. Name the language that has this.
For C it's normal because it does not have constructors/destructors, templates and other 'special' memory and resource management. C is designed so that it allows simply translate it's code into assembly code in mind and vice verse. Stroustroup called 'goto' statement 'evil' but didn't provide something for replacement.
Languages that allow 'break out the nested loop': Java, JavaScript, C#, D and even PERL.
FaTony wrote:char* is a C legacy. You need to pass std::vector<std::string>.
Even more. I can't pass std::vector<std::string> to the function that requires std::vector<const std::string>. Replacing char * to std::string does not solve the problem.
FaTony wrote:Every tool can be abused. If you find a library that makes the code ambiguous, find a better library.
You're wrong because C++ adepts say 'only this way is right' by providing such crap libraries like STL and Boost. I saw how one C++ adept tried to perform multithreaded IO on sockets with new libraries provided by C++ 11 standard. I couldn't read his code without many facepalms because there were a lot of hacks that could be avoided by just writing raw C-style code.
FaTony wrote:Just as I expected. You just couldn't learn proper C++. Maybe all you read was Russian books?
I've read Stroustroup's third edition book many years ago and wanted to be employeed as C++ developer. But, fortunately, PERL and JAVA was offered to me instead. Also I'm highly experienced in writing low-level assembly code. So I have a good base to perform comparison.
FaTony wrote:
Guess what, all my classes follow RAII, I never use error codes and always use exceptions, and about ~70% of all my code is templates. I've even written a
digital audio processing library that is 99% templates.
The only non-template part is reading and writing WAV files. Why? Because templates allow you to work with any type. In my library almost all class templates take sample type and allocator so all my classes templates work with any bit depth and allocator. Want 16, 24, 32 bit int? Supported out of the box. Want 64 bit int and 128 bit float? Write a 100 line class and the whole library suddenly supports it.
This?
Code: Select all
stream.Read(chunkid.data(), chunkid.size());
stream >> chunksize;
if (chunkid == FormatChunkID)
{
// Format chunk.
stream >> format;
stream >> numchannels;
stream >> samplerate;
std::uint32_t byterate;
stream >> byterate;
stream >> blockalign;
stream >> bitdepth;
if (chunksize == 16)
{
continue;
}
std::uint16_t extensionsize;
stream >> extensionsize;
// Skip extension bytes for now.
stream.SeekReadPosition(extensionsize, std::ios_base::cur);
}
Or this?
Code: Select all
template <typename T, typename Allocator>
void Pan<T, Allocator>::Render(MultichannelAudioBuffer<T, Allocator>& buffer)
{
if (buffer.GetNumberOfChannels() == 1)
{
buffer.ChannelPushBack(buffer[0].GetAudioBuffer());
}
else if (buffer.GetNumberOfChannels() != 2)
{
throw std::invalid_argument{"Pan::Render: Invalid number of channels."};
}
buffer[0] += leftgain;
buffer[1] += rightgain;
}
Or this?
Code: Select all
template <typename T, typename Allocator>
AmplifierMIDIControl<T, Allocator>::AmplifierMIDIControl(
Amplifier<T, Allocator>& amp, MIDI::InputChannel& channel,
Gain<CalcType> maxgain)
: amp{amp}, channel{channel}, maxgain{std::move(maxgain)}
{
cchook = channel.HookControlChange([&](const auto& event){
this->OnControlChange(event); });
this->SetGain();
}
Sorry, but for audio processing it's a holy crap. Because:
1. You have a lot of code overhead for processing one sample. For simple devices it's not noticeable. For devices that do complex processing it's a very huge performance penalty. Yes, it looks funny but doesn't solve the more foreground task: it should be fast as possible.
2. For audio processing on very popular x86 architecture float and double are enough to do many things. You do not need to support many sample formats.
3. The behaviour of fixed-point is very different to floating point, especially relative to overflows/undeflows. So you will be forced to completely rewrite your code for microcontrollers also for performance purposes.
Whenever I see the code which says "but then you need to call this function to clean this up", I'm like "O rly?
And this is is reasonalbe. All your RAII is powerless when the cleaning function takes a lot of time for execution or returns error code. When you use auto-destruction wrappers, you can not properly handle the behaviour of your code relative to long cleaning. Also you can not throw exceptions from destructors, surprise!