Hello Dou,
I tried to upload an attachement with a project to reproduce the issue, but zip is not allowed, and the maximum file size is 1.
So I tried to upload a .cpp file. Also not allowed. Strange that even text files like .cpp are not allowed.
Anyway, here is the content of the .cpp:
//#include <vsg/all.h>
//
//#include <vsgXchange/all.h>
//
//#include <algorithm>
//#include <chrono>
#include <iostream>
#include <thread>
namespace vsg
{
/// smart pointer that works with objects that have intrusive reference counting, such as all vsg::Object
/// broadly similar in role to std::shared_ptr<> but half size and faster thanks to lower memory footprint and better cache coherency
template<class T>
class ref_ptr
{
public:
using element_type = T;
ref_ptr() noexcept :
_ptr(nullptr) {}
ref_ptr(const ref_ptr& rhs) noexcept :
_ptr(rhs._ptr)
{
if (_ptr) _ptr->ref();
}
/// move constructor
template<class R>
ref_ptr(ref_ptr<R>&& rhs) noexcept :
_ptr(rhs._ptr)
{
rhs._ptr = nullptr;
}
template<class R>
ref_ptr(const ref_ptr<R>& ptr) noexcept :
_ptr(ptr._ptr)
{
if (_ptr) _ptr->ref();
}
explicit ref_ptr(T* ptr) noexcept :
_ptr(ptr)
{
if (_ptr) _ptr->ref();
}
template<class R>
explicit ref_ptr(R* ptr) noexcept :
_ptr(ptr)
{
if (_ptr) _ptr->ref();
}
// std::nullptr_t requires extra header
ref_ptr(decltype(nullptr)) noexcept :
ref_ptr() {}
~ref_ptr()
{
if (_ptr) _ptr->unref();
}
void reset()
{
if (_ptr) _ptr->unref();
_ptr = nullptr;
}
ref_ptr& operator=(T* ptr)
{
if (ptr == _ptr) return *this;
T* temp_ptr = _ptr;
_ptr = ptr;
if (_ptr) _ptr->ref();
// unref the original pointer after ref in case the old pointer object is a parent of the new pointer's object
if (temp_ptr) temp_ptr->unref();
return *this;
}
ref_ptr& operator=(const ref_ptr& rhs)
{
if (rhs._ptr == _ptr) return *this;
T* temp_ptr = _ptr;
_ptr = rhs._ptr;
if (_ptr) _ptr->ref();
// unref the original pointer after ref in case the old pointer object is a parent of the new pointer's object
if (temp_ptr) temp_ptr->unref();
return *this;
}
template<class R>
ref_ptr& operator=(const ref_ptr<R>& rhs)
{
if (rhs._ptr == _ptr) return *this;
T* temp_ptr = _ptr;
_ptr = rhs._ptr;
if (_ptr) _ptr->ref();
// unref the original pointer after ref in case the old pointer object is a parent of the new pointer's object
if (temp_ptr) temp_ptr->unref();
return *this;
}
/// move assignment
template<class R>
ref_ptr& operator=(ref_ptr<R>&& rhs)
{
if (rhs._ptr == _ptr) return *this;
if (_ptr) _ptr->unref();
_ptr = rhs._ptr;
rhs._ptr = nullptr;
return *this;
}
template<class R>
bool operator<(const ref_ptr<R>& rhs) const { return (_ptr < rhs._ptr); }
template<class R>
bool operator==(const ref_ptr<R>& rhs) const { return (rhs._ptr == _ptr); }
template<class R>
bool operator!=(const ref_ptr<R>& rhs) const { return (rhs._ptr != _ptr); }
template<class R>
bool operator<(const R* rhs) const { return (_ptr < rhs); }
template<class R>
bool operator==(const R* rhs) const { return (rhs == _ptr); }
template<class R>
bool operator!=(const R* rhs) const { return (rhs != _ptr); }
bool valid() const noexcept { return _ptr != nullptr; }
explicit operator bool() const noexcept { return valid(); }
// potentially dangerous automatic type conversion, could cause dangling pointer if ref_ptr<> assigned to C pointer and ref_ptr<> destruction causes an object delete.
operator T*() const noexcept { return _ptr; }
void operator[](int) const = delete;
T& operator*() const noexcept { return *_ptr; }
T* operator->() const noexcept { return _ptr; }
T* get() const noexcept { return _ptr; }
T* release_nodelete() noexcept
{
T* temp_ptr = _ptr;
if (_ptr) _ptr->unref_nodelete();
_ptr = nullptr;
return temp_ptr;
}
void swap(ref_ptr& rhs) noexcept
{
T* temp_ptr = _ptr;
_ptr = rhs._ptr;
rhs._ptr = temp_ptr;
}
template<class R>
ref_ptr<R> cast() const { return ref_ptr<R>(_ptr ? _ptr->template cast<R>() : nullptr); }
protected:
template<class R>
friend class ref_ptr;
T* _ptr;
};
class Object
{
public:
Object() {}
Object(const Object& object /*, const CopyOp& copyop = {}*/) {}
Object& operator=(const Object&);
static ref_ptr<Object> create() { return ref_ptr<Object>(new Object); }
static ref_ptr<Object> create_if(bool flag)
{
if (flag)
return ref_ptr<Object>(new Object);
else
return {};
}
/// provide new and delete to enable custom memory management via the vsg::Allocator singleton, using the MEMORY_AFFINTY_OBJECTS
//static void* operator new(std::size_t count);
//static void operator delete(void* ptr);
virtual std::size_t sizeofObject() const noexcept { return sizeof(Object); }
//virtual const char* className() const noexcept { return type_name<Object>(); }
/// return the std::type_info of this Object
virtual const std::type_info& type_info() const noexcept { return typeid(Object); }
virtual bool is_compatible(const std::type_info& type) const noexcept { return typeid(Object) == type; }
template<class T>
T* cast() { return is_compatible(typeid(T)) ? static_cast<T*>(this) : nullptr; }
template<class T>
const T* cast() const { return is_compatible(typeid(T)) ? static_cast<const T*>(this) : nullptr; }
/// clone this object using CopyOp's duplicates map to decide whether to clone or to return the original object.
/// The default clone(CopyOp&) implementation simply returns ref_ptr<> to this object rather attempt to clone.
//virtual ref_ptr<Object> clone(const CopyOp& copyop = {}) const;
/// compare two objects, return -1 if this object is less than rhs, return 0 if it's equal, return 1 if rhs is greater,
virtual int compare(const Object& rhs) const { return 0; }
//virtual void accept(Visitor& visitor);
//virtual void traverse(Visitor&) {}
//virtual void accept(ConstVisitor& visitor) const;
//virtual void traverse(ConstVisitor&) const {}
//virtual void accept(RecordTraversal& visitor) const;
//virtual void traverse(RecordTraversal&) const {}
//virtual void read(Input& input);
//virtual void write(Output& output) const;
// ref counting methods
inline void ref() const noexcept { _referenceCount.fetch_add(1, std::memory_order_relaxed); }
inline void unref() const noexcept
{
if (_referenceCount.fetch_sub(1, std::memory_order_seq_cst) <= 1) _attemptDelete();
}
inline void unref_nodelete() const noexcept { _referenceCount.fetch_sub(1, std::memory_order_seq_cst); }
inline unsigned int referenceCount() const noexcept { return _referenceCount.load(); }
/// meta data access methods
/// wraps the value with a vsg::Value<T> object and then assigns via setObject(key, vsg::Value<T>)
template<typename T>
void setValue(const std::string& key, const T& value);
/// specialization of setValue to handle passing C strings
void setValue(const std::string& key, const char* value) { setValue(key, value ? std::string(value) : std::string()); }
/// get specified value type, return false if value associated with key is not assigned or is not the correct type
template<typename T>
bool getValue(const std::string& key, T& value) const;
/// assign an Object associated with key
void setObject(const std::string& key, ref_ptr<Object> object) {}
/// get Object pointer associated with key, return nullptr if no object associated with key has been assigned
Object* getObject(const std::string& key);
/// get const Object pointer associated with key, return nullptr if no object associated with key has been assigned
const Object* getObject(const std::string& key) const;
/// get object pointer of specified type associated with key, return nullptr if no object associated with key has been assigned
template<class T>
T* getObject(const std::string& key) { return dynamic_cast<T*>(getObject(key)); }
/// get const object pointer of specified type associated with key, return nullptr if no object associated with key has been assigned
template<class T>
const T* getObject(const std::string& key) const { return dynamic_cast<const T*>(getObject(key)); }
/// get ref_ptr<Object> associated with key, return nullptr if no object associated with key has been assigned
ref_ptr<Object> getRefObject(const std::string& key);
/// get ref_ptr<const Object> pointer associated with key, return nullptr if no object associated with key has been assigned
ref_ptr<const Object> getRefObject(const std::string& key) const;
/// get ref_ptr<T> of specified type associated with key, return nullptr if no object associated with key has been assigned
template<class T>
ref_ptr<T> getRefObject(const std::string& key) { return getRefObject(key).cast<T>(); }
/// get ref_ptr<const T> of specified type associated with key, return nullptr if no object associated with key has been assigned
template<class T>
const ref_ptr<const T> getRefObject(const std::string& key) const { return getRefObject(key).cast<const T>(); }
/// remove meta object or value associated with key
void removeObject(const std::string& key) {}
// Auxiliary object access methods, the optional Auxiliary is used to store meta data
//Auxiliary* getOrCreateAuxiliary();
//Auxiliary* getAuxiliary() { return _auxiliary; }
//const Auxiliary* getAuxiliary() const { return _auxiliary; }
protected:
virtual ~Object() {}
virtual void _attemptDelete() const {}
// void setAuxiliary(Auxiliary* auxiliary);
private:
friend class Auxiliary;
mutable std::atomic_uint _referenceCount;
//Auxiliary* _auxiliary;
};
template<class ParentClass, class Subclass>
class Inherit : public ParentClass
{
public:
template<typename... Args>
Inherit(Args&&... args) :
ParentClass(std::forward<Args>(args)...) {}
template<typename... Args>
static ref_ptr<Subclass> create(Args&&... args)
{
return ref_ptr<Subclass>(new Subclass(std::forward<Args>(args)...));
}
template<typename... Args>
static ref_ptr<Subclass> create_if(bool flag, Args&&... args)
{
if (flag) return ref_ptr<Subclass>(new Subclass(std::forward<Args>(args)...));
return {};
}
std::size_t sizeofObject() const noexcept override { return sizeof(Subclass); }
//const char* className() const noexcept override { return type_name<Subclass>(); }
const std::type_info& type_info() const noexcept override { return typeid(Subclass); }
bool is_compatible(const std::type_info& type) const noexcept override { return typeid(Subclass) == type || ParentClass::is_compatible(type); }
int compare(const Object& rhs) const override
{
int result = ParentClass::compare(rhs);
if (result != 0) return result;
size_t startOfSubclass = sizeof(ParentClass);
size_t size = sizeof(Subclass) - startOfSubclass;
// Subclass adds no extra data to compare
if (size == 0) return 0;
const char* lhs_ptr = reinterpret_cast<const char*>(this);
const char* rhs_ptr = reinterpret_cast<const char*>(&rhs);
// compare the data that Subclass adds over ParentClass
return std::memcmp(lhs_ptr + startOfSubclass, rhs_ptr + startOfSubclass, size);
}
//void accept(Visitor& visitor) override { visitor.apply(static_cast<Subclass&>(*this)); }
//void accept(ConstVisitor& visitor) const override { visitor.apply(static_cast<const Subclass&>(*this)); }
//void accept(RecordTraversal& visitor) const override { visitor.apply(static_cast<const Subclass&>(*this)); }
};
class Instrumentation : public Inherit<Object, Instrumentation>
{
public:
Instrumentation() {}
virtual ref_ptr<Instrumentation> shareOrDuplicateForThreadSafety() { return ref_ptr<Instrumentation>(this); }
virtual void setThreadName(const std::string& /*name*/) const {
std::cout << "setThreadName";
};
void testFuncRef(ref_ptr<Instrumentation>& reference) {
reference->setThreadName("test");
}
void testFunc(ref_ptr<Instrumentation> reference)
{
reference->setThreadName("test");
}
//virtual void enterFrame(const SourceLocation* /*sl*/, uint64_t& /*reference*/, FrameStamp& /*frameStamp*/) const {};
//virtual void leaveFrame(const SourceLocation* /*sl*/, uint64_t& /*reference*/, FrameStamp& /*frameStamp*/) const {};
//virtual void enter(const SourceLocation* /*sl*/, uint64_t& /*reference*/, const Object* /*object*/ = nullptr) const {};
//virtual void leave(const SourceLocation* /*sl*/, uint64_t& /*reference*/, const Object* /*object*/ = nullptr) const {};
//virtual void enterCommandBuffer(const SourceLocation* /*sl*/, uint64_t& /*reference*/, CommandBuffer& /*commandBuffer*/) const {};
//virtual void leaveCommandBuffer(const SourceLocation* /*sl*/, uint64_t& /*reference*/, CommandBuffer& /*commandBuffer*/) const {};
//virtual void enter(const SourceLocation* /*sl*/, uint64_t& /*reference*/, CommandBuffer& /*commandBuffer*/, const Object* /*object*/ = nullptr) const {};
//virtual void leave(const SourceLocation* /*sl*/, uint64_t& /*reference*/, CommandBuffer& /*commandBuffer*/, const Object* /*object*/ = nullptr) const {};
virtual void finish() const {};
protected:
virtual ~Instrumentation() {}
};
} // namespace vsg
int main(int argc, char** argv)
{
vsg::ref_ptr<vsg::Instrumentation> resourceHints(new vsg::Instrumentation());
resourceHints->setThreadName("main"); // debugger steps into operator ->
resourceHints->finish(); // debugger steps into operator ->
vsg::ref_ptr<vsg::Instrumentation> resourceHints2(new vsg::Instrumentation());
resourceHints2->testFuncRef(resourceHints); // debugger steps into operator ->
resourceHints2->testFunc(resourceHints); // debugger steps into into operator -> AND ref_ptr
return 0;
/* debugger steps into these operators and functions, despite this in default.natstepfilter:
<Function><Name>Platform::EventSource::Invoke.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>IID_PPV_ARGS_Helper<.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>Microsoft::WRL::ComPtr<.*>::operator&</Name><Action>NoStepInto</Action></Function>
<Function><Name>Microsoft::WRL::ComPtr<.*>::operator-></Name><Action>NoStepInto</Action></Function>
<Function><Name>Microsoft::WRL::Details::ComPtrRef.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>operator new</Name><Action>NoStepInto</Action></Function>
<Function><Name>std::forward<.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>std::move<.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>operator new</Name><Action>NoStepInto</Action></Function>
<Function><Name>operator-></Name><Action>NoStepInto</Action></Function>
<Function><Name>T* operator-></Name><Action>NoStepInto</Action></Function>
<Function><Name>T*operator-></Name><Action>NoStepInto</Action></Function>
<Function><Name>*operator->()</Name><Action>NoStepInto</Action></Function>
<Function><Name>*operator->() const</Name><Action>NoStepInto</Action></Function>
<Function><Name>std::shared_ptr.+::operator-></Name><Action>NoStepInto</Action></Function>
<Function><Name>*shared_ptr*</Name><Action>NoStepInto</Action></Function>
<Function><Name>*shared_ptr.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>std::.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>osg::ref_ptr.+::operator-></Name><Action>NoStepInto</Action></Function>
<Function><Name>osg::ref_ptr.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>osg::ref_ptr*</Name><Action>NoStepInto</Action></Function>
<Function><Name>boost::.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>SoPtr*</Name><Action>NoStepInto</Action></Function>
<Function><Name>SoPtr.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>*c_str()</Name><Action>NoStepInto</Action></Function>
<Function><Name>*get()</Name><Action>NoStepInto</Action></Function>
<Function><Name>*::vec</Name><Action>NoStepInto</Action></Function>
<Function><Name>handle</Name><Action>NoStepInto</Action></Function>
<Function><Name>operator-> ()</Name><Action>NoStepInto</Action></Function>
<Function><Name>operator-></Name><Action>NoStepInto</Action></Function>
<Function><Name>operator+</Name><Action>NoStepInto</Action></Function>
<Function><Name>T*operator->()</Name><Action>NoStepInto</Action></Function>
<Function><Name>explicit operator bool () const</Name><Action>NoStepInto</Action></Function>
<Function><Name>ref_ptr()</Name><Action>NoStepInto</Action></Function>
<Function><Name>ref_ptr</Name><Action>NoStepInto</Action></Function>
<Function><Name>*ref_ptr<*></Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::ref_ptr.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::ref_ptr*</Name><Action>NoStepInto</Action></Function>
<Function><Name>t_vec3</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::t_vec3</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::t_vec3*</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::t_vec3.*</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::t_vec3::*</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::t_vec3::t_vec3</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::t_vec3.t_vec3</Name><Action>NoStepInto</Action></Function>
<Function><Name>vsg::t_vec3<*>::*</Name><Action>NoStepInto</Action></Function>
<Function><Name>create</Name><Action>NoStepInto</Action></Function>
*/
// clean up done automatically thanks to ref_ptr<>
return 0;
}