Home > Back-end >  c what does a dynamic cast of a unique pointer return?
c what does a dynamic cast of a unique pointer return?

Time:12-14

I am trying to use lambdas to find a way to find how many specific derived classes are in a vector of Base class type.

std::vector<std::unique_ptr<Account>> openedAccounts;

int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(), 
            [](std::unique_ptr<Account> ptr) { return dynamic_cast<Current&>(*ptr) != nullptr; }); // I will call this for savings as well

The account is a base abstract class and the current is a derived class.

I am getting the error no operator != matches these operands". HOwever, I thought dynamic cast can return a null ptr.

CodePudding user response:

A dynamic cast returns exactly what you asked for.

You asked for Current& or a Current reference.

You probably want to ask this

return dynamic_cast<Current*>(ptr.get()) != nullptr; 

CodePudding user response:

I thought dynamic cast can return a null ptr.

Only when you dynamic cast into a pointer type.

References don't have a representation for null. When you dynamic cast into a reference type, then an exception will be thrown in cases where a pointer cast would have returned null.

what is the way to go about this then?

dynamic_cast<Current*>(ptr.get())

would work. However, designs that require dynamic_cast are often probably bad. dynamic_cast exists for mostly working around badly designed APIs.

I recommend considering alternative designs.

CodePudding user response:

std::vector<std::unique_ptr<Account>> openedAccounts;

int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(), 
            [](std::unique_ptr<Account> ptr) { return dynamic_cast<Current&>(*ptr) != nullptr; }); // I will call this for savings as well

I see in this code 3 problems:

  1. dynamic_cast<Current&> ... != nullptr - dynamic_cast throws an exception for references and never returns null_ptr.
  2. Lambda is incorrect, since argument std::unique_ptr<Account> is an attempt to create a copy of something what should be unique.
  3. if you have container of pointers to some abstraction and you have to do dynamic_cast then this is clear indication that abstraction used is invalid.

So this should look looks more like this:

class Account {
public:
    virtual bool isCurrent() { return false; }
    ....
};

std::vector<std::unique_ptr<Account>> openedAccounts;

int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(), 
            [](const std::unique_ptr<Account>& ptr) { return ptr->isCurrent(); });

I undesutnd that last point is hard to process so here is the hacky fix:

int countCurrent = std::count_if(openedAccounts.begin(), openedAccounts.end(), 
            [](const std::unique_ptr<Account>& ptr) { return dynamic_cast<Current *>(ptr.get()) != nullptr; });
  • Related