Downcasting a base class in a container to a derived class - c++

I'll show my code first then explain my issue:
std::vector<std::unique_ptr<SGUIObject> > m_objects;
const std::unique_ptr<SGUIObject>& SGUIManager::getObject(const std::string& object_name)
{
for (auto const& iter : m_objects)
{
if (iter.get()->getObjectName() == object_name)
return iter;
}
}
//SButton is derived from SGUIObject
//m_clicked is a boolean member in SButton (private)
//isClicked is a public member method of SButton
const bool isClicked() const { return m_clicked; }
if (dynamic_cast<SButton>(SSceneManager::getGUIManager().getObject("testbutton").isClicked()))
std::cout << "Clicked!" << std::endl;
I just copy pasted from several different files, so it looks weird when all put together. Anyways, what I'm trying to do is downcast from a SGUIObject to a SButton and call isClicked() in an if/else loop. When I do my current code, Code::Blocks gives me this error:
error: 'const class std::unique_ptr' has no member named 'isClicked'|
I have a feeling I'm having a slight syntactical issue, and I'd be extremely grateful if someone was to explain it to me.
Thanks!

I think you mean:
dynamic_cast<SButton*>(SSceneManager::getGUIManager().getObject("testbutton").get())->isClicked()
You want to call isClicked on the result of the dynamic_cast, not the result of getObject.

This line has several problems:
if (dynamic_cast<SButton*>(SSceneManager::getGUIManager().getObject("testbutton").isClicked()))
First SSceneManager::getGUIManager().getObject("testbutton") return a unique_ptr reference. And as the compiler said, unique_ptr does not hae an isclicked method. For that, you would need to use the -> operator which is overloaded to return the underlying pointer.
Second, even if it worked, you can not dynamic_cast a bool to a pointer.
You could do something like
if (dynamic_cast<SButton*>(SSceneManager::getGUIManager().getObject("testbutton").get())->isClicked) ...
Although you might want to separate it in 2 lines to make sure dynamic_cast does not give you a NULL pointer.
SBButton* button = dynamic_cast<SButton*>(SSceneManager::getGUIManager().getObject("testbutton").get());
if (button && button->isClicked()) ...

Related

Downcasting trouble

This is my first experience with downcasting in C++ and I just can't understand the problem.
AInstruction and CInstruction inherit from AssemblerInstruction.
Parser takes the info in its ctor and creates one of those derived instruction types for its mInstruction member (accessed by getInstruction). In the program, a method of the base AssemblerInstruction class is used, for happy polymorphism.
But when I want to test that the Parser has created the correct instruction, I need to query the derived instruction members, which means I need to downcast parser.getInstruction() to an AInstruction or CInstruction.
As far as I can tell this needs to be done using a bunch of pointers and references. This is how I can get the code to compile:
TEST(ParserA, parsesBuiltInConstants)
{
AssemblerInstruction inst = Parser("#R3", 0).getInstruction();
EXPECT_EQ(inst.getInstructionType(), AssemblerInstruction::InstructionType::A);
AssemblerInstruction* i = &(inst);
AInstruction* a = dynamic_cast<AInstruction*>(i);
EXPECT_EQ(a->getLine(), "R3");
}
Running this gives this error:
unknown file: error: SEH exception with code 0xc0000005 thrown in the test body.
And stepping through the code, when the debugger is on the final line of the function, a is pointing to
0x00000000 <NULL>.
I imagine this is an instance where I don't have a full enough understanding of C++, meaning that I could be making a n00b mistake. Or maybe it's some bigger crazy problem. Help?
Update
I've been able to make this work by making mInstruction into a (dumb) pointer:
// in parser, when parsing
mInstructionPtr = new AInstruction(assemblyCode.substr(1), lineNumber);
// elsewhere in AssemblerInstruction.cpp
AssemblerInstruction* AssemblyParser::getInstructionPtr() { return mInstructionPtr; }
TEST(ParserA, parsesBuiltInConstants)
{
auto ptr = Parser("#R3", 0).getInstructionPtr();
AInstruction* a = dynamic_cast<AInstruction*>(ptr);
EXPECT_EQ(a->getLine(), "R3");
}
However I have trouble implementing it with a unique_ptr:
(I'm aware that mInstruction (non-pointer) is redundant, as are two types of pointers. I'll get rid of it later when I clean all this up)
class AssemblyParser
{
public:
AssemblyParser(std::string assemblyCode, unsigned int lineNumber);
AssemblerInstruction getInstruction();
std::unique_ptr<AssemblerInstruction> getUniqueInstructionPtr();
AssemblerInstruction* getInstructionPtr();
private:
AssemblerInstruction mInstruction;
std::unique_ptr<AssemblerInstruction> mUniqueInstructionPtr;
AssemblerInstruction* mInstructionPtr;
};
// in AssemblyParser.cpp
// in parser as in example above. this works fine.
mUniqueInstructionPtr = make_unique<AInstruction>(assemblyCode.substr(1), lineNumber);
// this doesn't compile!!!
unique_ptr<AssemblerInstruction> AssemblyParser::getUniqueInstructionPtr()
{
return mUniqueInstructionPtr;
}
In getUniqueInstructionPtr, there is a squiggle under mUniqueInstructionPtr with this error:
'std::unique_ptr<AssemblerInstruction,std::default_delete>::unique_ptr(const std::unique_ptr<AssemblerInstruction,std::default_delete> &)': attempting to reference a deleted function
What!? I haven't declared any functions as deleted or defaulted!
You can not downcast an object to something which doesn't match it's dynamic type. In your code,
AssemblerInstruction inst = Parser("#R3", 0).getInstruction();
inst has a fixed type, which is AssemblerInstruction. Downcasting it to AInstruction leads to undefined behavior - manifested as crash - because that is not what it is.
If you want your getInstruction to return a dynamically-typed object, it has to return a [smart] pointer to base class, while constructing an object of derived class. Something like that (pseudo code):
std::unique_ptr<AssemblerInstruction> getInstruction(...) {
return std::make_unique<AInstruction>(...);
}
Also, if you see yourself in need of downcasting object based on a value of a class, you are doing something wrong, as you are trying to home-brew polymorphism. Most of the times it does indicate a design flaw, and should instead be done using built-in C++ polymorphic support - namely, virtual functions.

how to correctly pass data structures between custom llvm passes

I have a Function pass, called firstPass, which does some analysis and populates:
A a;
where
typedef std::map< std::string, B* > A;
class firstPass : public FunctionPass {
A a;
}
typedef std::vector< C* > D;
class B {
D d;
}
class C {
// some class packing information about basic blocks;
}
Hence I have a map of vectors traversed by std::string.
I wrote associated destructors for these classes. This pass works successfully on its own.
I have another Function pass, called secondPass, needing this structure of type A to make some transformations. I used
bool secondPass::doInitialization(Module &M) {
errs() << "now running secondPass\n";
a = getAnalysis<firstPass>().getA();
return false;
}
void secondPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<firstPass>();
AU.setPreservesAll();
}
The whole code compiles fine, but I get a segmentation fault when printing this structure at the end of my first pass only if I call my second pass (since B* is null).
To be clear:
opt -load ./libCustomLLVMPasses.so -passA < someCode.bc
prints in doFinalization() and exits successfully
opt -load ./libCustomLLVMPasses.so -passA -passB < someCode.bc
gives a segmentation fault.
How should I wrap this data structure and pass it to the second pass without issues? I tried std::unique_ptr instead of raw ones but I couldn't make it work. I'm not sure if this is the correct approach anyway, so any help will be appreciated.
EDIT:
I solved the problem of seg. fault. It was basically me calling getAnalysis in doInitialization(). I wrote a ModulePass to combine my firstPass and secondPass whose runOnModule is shown below.
bool MPass::runOnModule(Module &M) {
for(Function& F : M) {
errs() << "F: " << F.getName() << "\n";
if(!F.getName().equals("main") && !F.isDeclaration())
getAnalysis<firstPass>(F);
}
StringRef main = StringRef("main");
A& a = getAnalysis<firstPass>(*(M.getFunction(main))).getA();
return false;
}
This also gave me to control the order of the functions processed.
Now I can get the output of a pass but cannot use it as an input to another pass. I think this shows that the passes in llvm are self-contained.
I'm not going to comment on the quality of the data structures based on their C++ merit (it's hard to comment on that just by this minimal example).
Moreover, I wouldn't use the doInitialization method, if the actual initialization is that simple, but this is a side comment too. (The doc does not mention anything explicitly about it, but if it is ran once per Module while the runOn method is ran on every Function of that module, it might be an issue).
I suspect that the main issue seems to stem from the fact A a in your firstPass is bound to the lifetime of the pass object, which is over once the pass is done. The simplest change would be to allocate that object on the heap (e.g. new) and return a pointer to it when calling getAnalysis<firstPass>().getA();.
Please note that using this approach might require manual cleanup if you decide to use a raw pointer.

C Style cast and C++ static_cast to reference of pointer

This is NOT C++11
I'm interested in the 3rd parameter of Microsoft's
CMapStringToOb::GetNextAssoc, which has following definition:
void GetNextAssoc(
POSITION& rNextPosition,
CString& rKey,
CObject*& rValue
) const;
Then I've got following easy code for testing: two good cases and one case with compiler error.
class CMyObject : public CObject //in order to use CMapStringToOb
{
public:
CMyObject(CString name_)
:name(name_)
{
}
void SayHello()
{
TRACE(_T("hello") + name);
}
CString name;
};
void main()
{
CMapStringToOb myMap;
myMap.SetAt(_T("a"), new CMyObject(_T("aaa")));
myMap.SetAt(_T("b"), new CMyObject(_T("bbb")));
myMap.SetAt(_T("c"), new CMyObject(_T("ccc")));
//good case 1
POSITION pos = myMap.GetStartPosition();
while (pos)
{
CString s;
CMyObject* pMine = NULL;
myMap.GetNextAssoc(pos, s, (CObject*&)pMine);
if(pMine)
{
pMine->SayHello();
}
}
//good case 2
pos = myMap.GetStartPosition();
while (pos)
{
CString s;
CObject* pObject = NULL;
myMap.GetNextAssoc(pos, s, pObject);
if(pObject)
{
CMyObject* pMine = static_cast<CMyObject*>(pObject);
pMine->SayHello();
}
}
//bad case:
//can not compile
// error C2440: 'static_cast' : cannot convert from 'CMyObject *' to 'CObject *&'
// static_cast and safe_cast to reference can only be used for valid initializations or for lvalue casts between related classes
pos = myMap.GetStartPosition();
while (pos)
{
CString s;
CMyObject* pMine = NULL;
myMap.GetNextAssoc(pos, s, static_cast<CObject*&>(pMine)); //compile error
if(pMine)
{
pMine->SayHello();
}
}
}
All I was trying to do is find an proper way to replace the C style casting to C++ style cast in this case.
Reading from this, it mentioned:
C casts are casts using (type)object or type(object). A C-style cast
is defined as the first of the following which succeeds:
const_cast
static_cast (though ignoring access restrictions)
static_cast (see above), then const_cast
reinterpret_cast
reinterpret_cast, then const_cast
Q1: Was the above list missing anything (e.g. for rValue)?
Q2: What's the proper way of translate C style cast to C++ style cast in this case ? (good case 2 works, but, is there a more concise one?)
Q3: How is the C Style cast doing for rValue? (in other words, please explain why good case 1 works)
You can't static_cast between references (or pointers) to "unrelated types." While you could static_cast from a CMyObject* to a CObject*, that isn't what you're doing here. Here you're trying to cast a reference to a pointer into a reference to another pointer. And the two pointer types do not have an inheritance relationship.
I like your "good case 2" code--I'd run with that.
For more details on the non-relatedness of your pointer types, see here: static_cast and reference to pointers
Inspired by John Zwinck, I will look from a different angle:
static_cast<CObject*>(pMine)
will succeed because type "CMyObject" generalize from type "CObject"; actually, this is done implicitly;
static_cast<CMyObject*>(pObject)
will succeed because type "CMyObject" generalize from type "CObject";
static_cast<CObject**>(&pMine)
will FAIL because type "CMyObject*" does NOT generalize from type "CObject*";
reinterpret_cast<CObject**>(&pMine)
will succeed at compile time because of "reinterpret_cast"; how about run time?
Let's make an assumption of the possible new implementation:
void CMapStringToOb::GetNextAssoc(
POSITION& rNextPosition,
CString& rKey,
CObject** ppValue)
{
*ppValue = (the pointer at the current position, point to an instance of "CMyObject");
}
So with calling this function by:
GetNextAssoc(pos, s, reinterpret_cast<CObject**>(&pMine))
the result is that "pMine" is pointing to an instance of "CMyObject";
So runtime is SAFE.
However, if we insert the key-value by (Note: CYourObject has no generalize relationship to CMyObject)
myMap.SetAt(_T("a"), new CYourObject(_T("aaa")));
and get it out by
GetNextAssoc(pos, s, reinterpret_cast<CObject**>(&pMine));
Compile time will still succeed, however, pMine is now pointing to "CYourObject", which will be UNDEFINED BEHAVIOR at runtime. (static_cast has the same issue, though)
The proper way to write that code would be to use std::map<>. Even if you insist on keeping the existing code mostly, consider fixing the interface of GetNextAssoc() to just return the pointer. In order to do that, you could simply add an overload of that function:
CObject* GetNextAssoc(
POSITION& rNextPosition,
CString& rKey,
) const {
CObject* res = 0;
GetNextAssoc(rNextPosition, rKey, res);
return res;
}
Even more, you could template that function and do the conversion to the target type there. Also, you could then use dynamic_cast, which should be used because formally, the container stores CObjects and they could have various, different types.
Now, why did I partially ignore your question? The reason is that the MFC don't follow modern coding style and in some cases, they simply do things that are frowned on. There are a bunch of justifications for that behaviour, but foremost it is age (didn't know better, didn't have proper template support) combined with compatibility concerns (can't change that now). That's not a reason to repeat these mistakes though.

all_of asking for argument list

After using all_of succesfully once I tried to do it again.
if (all_of(Enemies.begin(), Enemies.end(), in_lock_range))
{
lock_on = -1;
}
The vector is:
std::vector<Enemy> Enemies;
The function is:
bool Player::in_lock_range(Enemy arg)
{
if (get_distance(mouseTarget.x, mouseTarget.y, arg.x, arg.y) > arg.erect.r) return true;
else return false;
}
get_distance(x1,x2,y1,y2) returns the distance from 2 points
Enemy is a friend class to Player and vice versa so they use each other's stuff freely.
The error I recieve is
error C3867: 'Player::in_lock_range': function call missing argument list; use '&Player::in_lock_range' to create a pointer to member
I'm not sure why he is apparently asing for agruments for in_lock_range when I don't believe it needs any when in all_of, as I have used it in a different situation with no such issue.
Can anyone please explain to me what the cause of this can be? I am not really experienced in this. Thanks.
It's a member function, so the syntax for taking a pointer is
&Player::in_lock_range
This is only usable if it's a static member, since it must be callable with just a single argument. I'm guessing it isn't - presumably mouseTarget is a non-static data member of Player. In that case, you'll have to bind it to some player object:
bind(&Player::in_lock_range, std::ref(some_player), std::placeholders::_1)
or wrap it in a lambda:
[&](const Enemy& e){return some_player.in_lock_range(e);}
The function should probably take its argument by constant reference rather than value; and you might want to simplify the return statements
if (whatever) return true;
else return false;
to the more readable
return whatever;

Can I make the ternary operator treat my class like a bool?

I've recently been doing a huge refactoring where I was changing a lot of my code to return booleans instead of an explicit return code. To aid this refactoring I decided to lean on the compiler where possible by getting it to tell me the places where my code needed to be changed. I did this by introducing the following class (see here for the lowdown on how this works):
///
/// Typesafe boolean class
///
class TypesafeBool
{
private:
bool m_bValue;
struct Bool_ {
int m_nValue;
};
typedef int Bool_::* bool_;
inline bool_ True() const { return &Bool_::m_nValue; }
inline bool_ False() const { return 0; }
public:
TypesafeBool( const bool bValue ) : m_bValue( bValue ){}
operator bool_() const { return m_bValue ? True() : False(); }
};
Now, instead of using a normal bool type as the return type, I used this class which meant that I couldn't compile something like this any more:
TypesafeBool SomeFunction();
long result = SomeFunction(); // error
Great: it has made the refactoring manageable on a huge codebase by letting the compiler do a lot of the hard work for me. So now I've finished my refactoring and I'd quite like to keep this class hanging around and carry on using it since it affords us an extra level of safety that the built-in bool type doesn't.
There is however one "problem" which is preventing me from doing this. At the moment we make heavy use of the ternary operator in our code, and the problem is that it is not compatible with this new class without explicit casts:
TypesafeBool result = ( 1 == 2 ? SomeFunction() : false ); // error: different types used
TypesafeBool result = ( 1 == 2 ? SomeFunction() : (TypesafeBool)false );
If I could "solve" this issue so that I could use my class in a seamless manner I would probably carry on using it throughout the codebase. Does anyone know of a solution to this issue? Or is it just impossible to do what I want?
In the context of the conditional operator, the type of the expression is the common type of the last two operands. The complete rules to determine this common type are a bit complex, but your case happens to be trivial: if one of the two possible return values is a class type, the other value must have the same class and the common type is obviously also that class.
That means that if one of the operands is a TypesafeBool, then the other must be as well.
Now the problem you're really trying to solve has been solved before. The trick is not providing a class; instead use a typedef. See for instance safe bool.
class CCastableToBool
{
public:
// ...
operator bool() const
{
//...
{
return true;
}
//...
return false;
}
private:
// ...
};
but beware, in C++ it is considered really dangerous to have a class that can be casted to bool. You are warned :-)
you can read this there, SafeBool
You should explicitely call TypesafeBool::True() in all your ternary tests.
TypesafeBool result = ( 1 == 2 ? SomeFunction().True() : false );
I don't know about a seamless manner, the ternary operator has some restrictions on its use...
However, why don't you define two constants ?
TypesafeBool const True = TypesafeBool(true);
TypesafeBool const False = TypesafeBool(false);
And then:
TypesafeBool result = ( 1 == 2 ? SomeFunction() : False );
Of course, it's a bit unorthodox since I play on the capitalization to avoid reusing a reserved word :)
Is it a possibility to make the constructor of TypesafeBool explicit? Of course, now the usage has to be
TypesafeBool result( 1 == 2 ? b : false );
Could you use an assignment operator that takes in a bool as the external argument, as well as one that takes a TypesafeBool? It might be something to try out...
Nice try, but if your code base is large, you are probably better off using a static checker such as PC-Lint to look for implicit bool<->int conversions instead.