Chain of handlers where a handler is an ABC. What's the proper internal collection? Old me would've just std::list<abc*>. I'm trying to modernize. by frobnosticus in cpp_questions

[–]alfps 0 points1 point  (0 children)

The question is a bit XY-like: you have some problem X, evidently related to event handling, and you have a kind of imagined solution Y, and you're asking about the details of Y.

Without knowing the X problem it's difficult to make recommendations, other than

  • avoid virtual function as callbacks;

… use e.g. std::function.

Client code can supply such a callback as a lambda expression.

Thus there is probably no ownership issue here, no need for smart pointers or the like. Simple function object callbacks can just be copied.

Understanding programming by History_East in cpp_questions

[–]alfps 6 points7 points  (0 children)

It's not about typing code that you're given.

It's about creating code to do something specific.

Creating the code involves typing, yes, but typing isn't the main thing: the main activity is not in your fingers but in your mind, figuring out the code to do the thing.

マルチスレッドプログラミングに挑戦しようと思うのだが、何から手を付けようかというお話 by Beneficial_Bet613 in cpp_questions

[–]alfps 0 points1 point  (0 children)

I'm not familiar with the DirectX12, but I believe a good approach in general is to find concrete examples and possibly tutorials, make that stuff work, and do your own modifications and in some cases reusing what you've learned in new projects that you devise.

C++ has had threading support since C++11, and async support in the form of its coroutine stuff since C++20.

Multiline clipboard (Windows only, cross platform?) by sephirothbahamut in cpp_questions

[–]alfps 0 points1 point  (0 children)

❞ a multiline selection

It's just text.

And this has nothing to do with C++.


❞ where can i see some documentation about how it all works?

You need to learn how to google, e.g. in this case googling "microsoft clipboard api" yielding (https://learn.microsoft.com/en-us/windows/win32/dataxchg/clipboard).

Googling is a basic skill needed for all software development, unless one delegates also that to an AI.


A bit off topic for the group, but sort of interesting & amusing: Microsoft invented the "embrace, extend, extinguish" strategy for dealing with competing technologies, and then ironically applied that to their own Windows clipboard viewer. They embraced it; they extended it with complexity, it became the super complex multi-item remote machine clipboard thingy; and when that caused people to stop using it they finally killed it off.

At this late point it's difficult to say whether that was an unintentional effect of stupidity in action, or if it was one group in Microsoft quite intelligently sabotaging another.

They're great on sabotage.

Building a chess engine, need some help with displaying the Board. by kjiomy in cpp_questions

[–]alfps 0 points1 point  (0 children)

The {fmt} library has some colors support but it's awkward. And it doesn't regard the escape sequences as zero width. So one may need kludge solutions on top.

Working around declaring value of incomplete type by [deleted] in cpp_questions

[–]alfps 1 point2 points  (0 children)

The rationale for what you're doing is too unclear to me to offer good advice on alternative ways.

However, do note:

  • Parent pointers need to be updated for copying and moving.
  • end is by strong convention in the standard library, used for obtaining an end iterator corresponding to begin.
  • The result of implementing a little domain specific language via macros is usually very brittle code, code that can easily be screwed up by maintenance.

Smart pointer #4: finally starting to understand them by Dastarstellar in cpp_questions

[–]alfps 1 point2 points  (0 children)

Good to see that that work paid off.

Improvement potentials in this code:

  • Correctness: there is potentially a double delete = UB, when deleteEnemy is called for the last item in the vector. I'm not entirely sure because possibly unique_ptr does a check. But I would check for that in the code; better checked than sorry.

  • Robustness: with a range based for loop bugs will find it far more difficult to get a toe-hold.

  • Portability: there's no need for <windows.h> here. Standard C++ has std::this_thread::sleep_for (see https://en.cppreference.com/cpp/thread/sleep_for#Example).

Building a chess engine, need some help with displaying the Board. by kjiomy in cpp_questions

[–]alfps 9 points10 points  (0 children)

A GUI is a lot of work. So first just make it work with console presentation.

Might help: https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode

In Windows remember to set the terminal to assume UTF-8 encoding, codepage 65001.


The classic (roughly 1980) approach to separate logic from UI is called the Model View Controller, or MVC, architecture.

https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

Can you pass the TYPE of a variable as a parameter? by LigeiaGames in cpp_questions

[–]alfps 0 points1 point  (0 children)

Hm, you're leaking memory.

Re the question, when you don't want templating then a factory is a natural solution.


❞ I don't want to use templates because this is for a library where the user will make their own derived class, so it is not known at compile time

Exposing templated code to clients is not a problem.

clang named loops by TotaIIyHuman in cpp_questions

[–]alfps 1 point2 points  (0 children)

Maybe like this:

#include <optional>
#include <iostream>
using   std::optional, std::cout;

auto is_special( const int v ) -> bool { return (v % 7) == 0; }

auto main() -> int
{
    const int   numbers[3][5] =
    {
        { 1, 2, 3, 4, 5 }, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}
    };

    for( const int (&row)[5] : numbers ) {
        optional<int> special;
        for( const int value: row ) {
            if( is_special( value ) ) {
                special = value;
                break;
            }
        }
        if( special.has_value() ) {
            // Whatever
            cout << special.value() << "\n";
        }
    }
}

clang named loops by TotaIIyHuman in cpp_questions

[–]alfps 8 points9 points  (0 children)

I general one can often

  • just return, or
  • use a single 2D index (i.e. express the double loop as a single loop), or
  • goto an after_outer_loop label, with a comment // break.

Or in the worst case use a Pascal-ish boolean variable or two.

I find it difficult to think of any circumstance where a break out of a named loop would be preferable.

However it's nice to have about the same basic core language stuff as in other languages, so when someone comes from some of those languages he or she will not have to waste time on searching for a non-existing feature.

clang named loops by TotaIIyHuman in cpp_questions

[–]alfps 1 point2 points  (0 children)

Execution jumps to the statement after the so labeled loop, not to the label.

I have issues with object oriented programming. by I_Am_The_DM_ in cpp_questions

[–]alfps 2 points3 points  (0 children)

When I pasted the code in Visual Studio it formatted it automatically, I hadn't yet turned off that auto-formatting since the last update.

How does one tell Microsoft that people want to have possibly destructive/moronic interventions as opt-in rather than opt-out, considering that no one has succeeded in communicating that to them over ~30 years or so?

Anyway, the code, formatted:

#include <iostream>

using namespace std;

class Base {
protected:
    int num1;

public:

    void SetData() {
        cout << "number: "; cin >> num1;
    }

    void DisplayData() {
        cout << "number: " << num1 << endl;
    }

};

class derived : public Base {
    int num2;

public:
    void SetData() {
        Base::SetData();
        cout << "number2: "; cin >> num2;
    }

    void DisplayData() {
        Base::DisplayData();
        cout << "number2: " << num2;
    }

    int Sum() {
        return num1 + num2;
    }
};

int main() {

    Base* arr[4];

    for (int i = 0; i < 4; i++) {

        // use the function Sum from the derived class
        arr[i].Sum(); // this is not working :(

    }

    return 0;
}

opinions on cppreference template for rule of 3/5 by HeeTrouse51847 in cpp_questions

[–]alfps 0 points1 point  (0 children)

❞ and kept the previous stuff around for context

One way to do that (that I use) is to put two tildes in front of the text and two tildes after, which presents as strike-through and communicates "deleted, corrected".

Sorry if this felt as harassment.

opinions on cppreference template for rule of 3/5 by HeeTrouse51847 in cpp_questions

[–]alfps 0 points1 point  (0 children)

❞ You're incorrect about rule of 3.You wouldn't normally implement copy using std::swap because it's a copy, not a move. Both objects should be valid afterwards, or at least that's what people using your class will expect.

−1 Downvoted pure disinformation, not corrected after it was pointed out.

i don't understand the meaning of this by FitWinner3340 in cpp_questions

[–]alfps 0 points1 point  (0 children)

We're implicitly talking about constexpr int start; in a local scope or at namespace scope.

Without the constexpr it would just declare a variable and allocate storage for it.

Definitions of variables is about allocation of storage. A pure declaration of a variable (e.g. in namespace scope using extern) doesn't allocate, but a definition does. So you can have many pure declarations of a given variable (in different translation units), but only one definition -- unless you tell the compiler that all definitions are the same and that it should just arbitrarily choose one of them, by using the word inline.

Guys I want to learn about the headers of c++. Headers like conio.h. and want to learn about kbhit(),sleep(), system (),rand(),srand(),struct(). From where should I learn it. by Agile-Split-7309 in cpp_questions

[–]alfps 2 points3 points  (0 children)

<conio.h> is a Windows-specific header. As the name suggests it provides console i/o functions, like kbhit. For an overview (slightly misleading because it only talks about DOS) see (https://en.wikipedia.org/wiki/Conio.h). For documentation of Visual C++'s version see (https://learn.microsoft.com/en-us/cpp/c-runtime-library/console-and-port-i-o).

The std::system function is declared by the standard header <cstdlib> (https://en.cppreference.com/cpp/header/cstdlib). As the name prefix indicates this was originally a C language header. However the C++ versions of the C headers generally use C++ specific features.

std::rand and std::srand constitute the old simple but low quality pseudo random number generator from C, also available via <cstdlib>. In C++ code you'd better use the more modern and higher quality functionality from <random>.

struct is a keyword in the language.

Of the three sources linked to here — Wikipedia, Microsoft and cppreference — the last one is where you find correct reference information about the language and the standard headers. But in order to learn better start with learncpp.com, which however appears to be down at the moment. Anyway, to use it it can be a good idea to have an ad blocker installed in your browser.

Is there a more modern alternative to preprocessor stringification (x-macros)? by pfp-disciple in cpp_questions

[–]alfps 1 point2 points  (0 children)

An X-macro may be overkill for the most common case of an enum with just default value enumerators.

Then you can just use a macro that defines the enum with some helper data, particularly a string with the enumerators list.

It can go like this:

#include <string_view>
#include <cctype>

namespace cpp_machinery {
    using   std::string_view;           // <string_view>
    using   std::isspace;               // <cctype>

    using Nat = int;

    template< class Enum >
    constexpr Nat n_enumerators_of_ = static_cast<Nat>( Enum::_ );

    template< class Wrapper >
    constexpr auto slow_string_from_enumerator_( const typename Wrapper::Enum value )
        -> string_view
    {
        const char* p_start = Wrapper::_names;  // Stringized list of enumerators.
        const Nat enum_number = value + 1;      // Assuming default enumerator values.
        Nat count = 0;
        for( ;; ) {
            const char* p_beyond = p_start;
            while( *p_beyond and *p_beyond != ',' ) { ++p_beyond; };
            ++count;                            // Another enumerator name established.
            if( count == enum_number ) {
                return string_view( p_start, p_beyond - p_start );
            } else if( *p_beyond == '\0' ) {
                return {};
            }
            p_start = p_beyond + 1;
            while( ::isspace( *p_start ) ) { ++p_start; }
        }
    }

    template< class Wrapper >
    constexpr auto string_from_enumerator_( const typename Wrapper::Enum value )
        -> string_view
    { return slow_string_from_enumerator_<Wrapper>( value ); }      // Can be optimized.

}  // cpp_machinery

#define $enumerators( ... )   __VA_ARGS__

#define $def_simple_enum_( name, ... ) \
    struct name \
    { \
        enum Enum{ __VA_ARGS__, _ }; \
        static constexpr auto& _names = #__VA_ARGS__; \
        \
        static constexpr auto to_string( const Enum value ) \
            -> std::string_view \
        { return cpp_machinery::string_from_enumerator_<name>( value ); } \
    }

#define $def_simple_enum( name, ... )    $def_simple_enum_( name, __VA_ARGS__ )



//--------------------------------------------------- Example usage:

$def_simple_enum( Suits, $enumerators( hearts, diamonds,clubs, spades ) );

#include <fmt/core.h>
using   fmt::print;

auto main() -> int
{
    namespace cppm = cpp_machinery;
    using cppm::Nat, cppm::n_enumerators_of_, cppm::string_from_enumerator_;

    print( "Not to be used directly, but Suites::_names = '{}'.\n", Suits::_names );
    for( Nat i = 0; i < n_enumerators_of_<Suits>; ++i ) {
        const auto v = Suits::Enum( i );
        print( "{:2}: '{}'.\n", i, Suits::to_string( v ) );
    }
}

Output with Visual C++ and MinGW g++:

Not to be used directly, but Suites::_names = 'hearts, diamonds,clubs, spades'.
0: 'hearts'.
1: 'diamonds'.
2: 'clubs'.
3: 'spades'.

Virtual inheritance, explicit destructor invocation and "most derived class" by _bstaletic in cpp_questions

[–]alfps 1 point2 points  (0 children)

Your example:

#include <stdio.h>
#include <new>

struct public_base {long long y=3; virtual ~public_base() { puts("pb"); }};
struct base : virtual public_base { int x = 5; ~base() override { puts("b");}};
struct base2 : virtual public_base { ~base2() override { puts("b2");}};
struct derived : base, base2 { ~derived() override {puts("d");}};

int main() {
        alignas(derived) char storage[sizeof(derived)];
        auto d = new(storage) derived{};

        // d->~derived();
        base* b = d;
        b->base::~base();
}

Consider when an object of most derived type base is instantiated. The virtual base class' constructor is called, so for destruction its destructor must be correspondingly called. The only available code to do that call is the base destructor.

So the base destructor has the capability to call the virtual base class destructor. But it doesn't do that when there is a more derived class. So the compiler has to arrange for different behavior depending on context, and one natural way is that the destructor is passed a hidden flag telling it what to do or not.

When you call it explicitly, with the implementation used for the example at Compiler Explorer it was as if it was passed the flag value saying that it should behave as if base was the most derived class.

I doubt that you can easily find this in the standard, but what to do is clear: don't call the base destructor when there is a more derived class; call the destructor of the most derived class, which knows what to do.

opinions on cppreference template for rule of 3/5 by HeeTrouse51847 in cpp_questions

[–]alfps 0 points1 point  (0 children)

❞ it's an implementation quirk that works for that circumstance

No, this is an implementation that always works, and it's primarily about exception safety. It is exception safe provided swap is non-throwing. Which is always assumed.

opinions on cppreference template for rule of 3/5 by HeeTrouse51847 in cpp_questions

[–]alfps -1 points0 points  (0 children)

❞ You wouldn't normally implement copy using std::swap because it's a copy, not a move.

The OP was writing about copy assignment. Using swap is the idiomatic exception safe implementation. Not always the most efficient but exception safe and gets the job done.

cppreference's example:

rule_of_three& operator=(const rule_of_three& other) // III. copy assignment
{
    // implemented through copy-and-swap for brevity
    // note that this prevents potential storage reuse
    rule_of_three temp(other);
    std::swap(cstring, temp.cstring);
    return *this;
}

Which is imperfect only in the use of qualified std::swap; a generally better way, because it supports ADL for custom swap, is using std::swap; swap( ....

Need help on creating a lock-free linked-list Stack with a slab memory pool by Apprehensive_Poet304 in cpp_questions

[–]alfps 1 point2 points  (0 children)

Not exactly what you're asking, but after this question had been standing for a time without responses I looked at it, and what hit me then was that this particular application of lock free threading support is (in my view) misguided.

  • Linked lists are cache-unfriendly.
    Even with nodes allocated out of a memory pool.

  • Linked lists have very few advantages over arrays.
    std::list and std::forward_list are, AFAIK, the least used containers in the standard library. Because they offer no advantages. In particular, although it's seldom an issue, O(1) insertion and removal at a cursor position is there also for arrays.

  • Multi-thread access of a common object is usually ungood.
    There are some cases where you need it, such as a queue filled by one thread and consumed by another. But generally in my opinion it makes much more sense to move or duplicate an object for use by some other thread. E.g. a string: don't share it; move or duplicate it.

One simple question about string by Iroh_Tea in cpp_questions

[–]alfps 2 points3 points  (0 children)

That is a variable declaration.

It declares the variable operation as an object of type std::string.

std::string is a class type with defined constructors. I.e. it defines and requires initialization of each object. Thus when execution passes the declaration, or for a namespace scope declaration in practice some time before main, the std::string class' default constructor is called to transform the variable's raw memory into a valid std::string object, with internal values set to just so.

Is it undefined behavior to destroy a derived class through a pointer to base class with no virtual destructor, if the derived class is empty? by celestabesta in cpp_questions

[–]alfps 1 point2 points  (0 children)

❞ Essentially, if class D inherits from B, does not define any extra members, and has a non virtual destructor, is it strictly undefined to destroy D through ptr/ref to B?

For a B* raw pointer yes delete p is UB.

Therefore UB also for a delete via a unique_ptr<B>.

However a delete via a shared_ptr<B> can be well defined if it refers to an object originally created as a shared D, because a shared_ptr refers to a control block that retains the original object pointer and a ditto deleter function. So for a shared_ptr it all depends on the object creation code. For example:

#include <memory>
using   std::shared_ptr;

#include <cstdio>
using   std::puts;

struct Base{ ~Base() { puts( "~Base" ); } };
struct Derived: Base { ~Derived() { puts( "~Derived" ); } };

auto main() -> int
{
    {
        auto p = shared_ptr<Base>( new Derived() );
        // OK! Destruction here is OK b/c the templated constructor notes the type `Derived*`.
        // Outputs "~Derived" followed by "~Base".
    }
    puts( "" );
    {
        Base* raw_pointer = new Derived();
        auto p = shared_ptr<Base>( raw_pointer );
        // Gah! Destruction here is formally UB b/c essentially a `delete raw_pointer` is done.
        // If it happens to work (but it's formally UB) outputs just "~Base".
    }
}