Skip to content

Commit

Permalink
SafePtr: cast ok or ret null
Browse files Browse the repository at this point in the history
  • Loading branch information
fchn289 committed Jun 28, 2024
1 parent 425ee04 commit e3dbd63
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 20 deletions.
31 changes: 18 additions & 13 deletions src/safe_mem/SafePtr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,25 +105,25 @@ shared_ptr<To> SafePtr<T>::cast() const noexcept
{
if constexpr(is_base_of_v<To, T>) // safer than is_convertible()
{
//HID("(SafePtr) cast derived->base/self"); // ERR() not MT safe
return pT_;
//HID("(SafePtr) cast to base/self"); // ERR() not MT safe
return dynamic_pointer_cast<To>(pT_); // private/protected inherit will compile err(rare & no easy fix)
}
else if constexpr(is_void_v<To>) // else if for constexpr
else if constexpr(is_base_of_v<T, To>) // else if for constexpr
{
//HID("(SafePtr) cast any->void (for container to store diff types)");
return pT_;
//HID("(SafePtr) cast to derived");
return dynamic_pointer_cast<To>(pT_);
}
else if constexpr(is_base_of_v<T, To>)
else if constexpr(is_void_v<To>)
{
//HID("(SafePtr) cast base->derived");
return dynamic_pointer_cast<To>(pT_);
//HID("(SafePtr) cast to void (for container to store diff types)");
return pT_;
}
else if constexpr(!is_void_v<T>)
{
HID("(SafePtr) casting from=" << typeid(T).name() << " to=" << typeid(To).name());
return this; // c++17: force compile-err, safer than ret pT_ or null
//return nullptr; // c++14
HID("(SafePtr) invalid nonVoid-to-nonVoid, from=" << typeid(T).name() << " to=" << typeid(To).name());
return nullptr; // cast ok or null
}

else if (type_index(typeid(To)) == realType_)
{
//HID("(SafePtr) cast void->origin");
Expand All @@ -135,8 +135,7 @@ shared_ptr<To> SafePtr<T>::cast() const noexcept
return static_pointer_cast<To>(pT_);
}
HID("(SafePtr) can't cast from=void/" << typeid(T).name() << " to=" << typeid(To).name());
// realType_ & diffType_ can't compile-check so has to ret null (than eg dyn-cast that always fail compile)
return nullptr;
return nullptr; // since dynamic_pointer_cast<To>(pT_) may fail compile DataStore::get(); cast or or null
}

// ***********************************************************************************************
Expand Down Expand Up @@ -225,6 +224,7 @@ struct std::hash<RLib::SafePtr<T>>
// 2024-02-13 CSZ 2)usage in dom lib
// 2024-04-17 CSZ 3)strict constructor - illegal->compile-err (while *cast() can ret null)
// 2024-05-06 CSZ - AI-gen-code
// 2024-06-28 CSZ - dynamic_pointer_cast ok or ret null
// ***********************************************************************************************
// - Q&A
// . How to solve safety issue:
Expand Down Expand Up @@ -254,6 +254,11 @@ struct std::hash<RLib::SafePtr<T>>
// . it's possible but rare to use T* unsafely - SafePtr has this risk to exchange convenient
// . shared_ptr reduces mem-lifecycle-mgmt(1 major-possible-bug) - so worth
//
// . why cast ok or null instead of compiling err?
// . copy constructor is ok or compiling err; they cover diff scenario
// . unique ret is predictable & simple
// . dynamic_cast & dynamic_pointer_cast mostly follow the same rule
//
// . std::any vs SafePtr
// . SafePtr is safe shared_ptr that is lifecycle ptr, std::any is not ptr nor lifecycle mgmt
//
Expand Down
13 changes: 6 additions & 7 deletions ut/safe_mem/SafePtrTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,18 @@ TEST(SafePtrTest, GOLD_safeCast_self_base_void_back)

EXPECT_EQ(1, dynamic_pointer_cast<Derive>(dynamic_pointer_cast<void>(dynamic_pointer_cast<Base>(d)))->value()) << "REQ: ->void & void->origin";
EXPECT_EQ(1, dynamic_pointer_cast<Base >(dynamic_pointer_cast<void>(dynamic_pointer_cast<Base>(d)))->value()) << "REQ: ->void & void->preVoid";

//EXPECT_EQ(1, dynamic_pointer_cast<Base>(dynamic_pointer_cast<void>(make_safe<Derive>())).get()) << "safe cast, but not support";
}
struct D_protect : protected Derive { int value() const override { return 2; } };
struct D_private : private Derive { int value() const override { return 3; } };
TEST(SafePtrTest, invalidCast_retNull)
{
EXPECT_EQ(nullptr, dynamic_pointer_cast<Derive>(make_safe<Base>()).get()) << "REQ: invalid base->derived";

//dynamic_pointer_cast<char>(make_safe<int>(7)); // invalid cast, will compile err (safer than ret nullptr)

EXPECT_EQ(nullptr, dynamic_pointer_cast<Base>(dynamic_pointer_cast<void>(make_safe<Derive>())).get()) << "REQ: invalid derived->void->base";
EXPECT_EQ(nullptr, dynamic_pointer_cast<char >(make_safe<int >(7)).get()) << "REQ: invalid int ->char";
EXPECT_EQ(nullptr, dynamic_pointer_cast<Derive>(make_safe<Base>() ).get()) << "REQ: invalid base->derived";

//dynamic_pointer_cast<Base>(make_safe<D_private>()); // invalid private->base, will compile err
//dynamic_pointer_cast<Base>(make_safe<D_protect>()); // invalid protect->base, will compile err
//EXPECT_EQ(nullptr, dynamic_pointer_cast<Base>(make_safe<D_private>()).get()); // invalid, not ret null but compile err
//EXPECT_EQ(nullptr, dynamic_pointer_cast<Base>(make_safe<D_protect>()).get()); // invalid, not ret null but compile err
}
struct D2 : public Derive { int value() const override { return 2; } };
TEST(SafePtrTest, safe_cast_bugFix)
Expand Down

0 comments on commit e3dbd63

Please sign in to comment.