In my code below, I am creating a class that takes in variables using operator<< and processes the variables accordingly. The exact logic that will go inside the class is omitted for simplicity & clarity.
The issue that I'm facing is that when I try to create an anonymous instance of the object, and use that directly with the (<<) operator, most compilers would complain - something along the lines of (no match for 'operator<<')
From what I understand, calling the class directly ( TestObject() ) is a legal expression, and it should instantiate an anonymous object that gets passed into the operator.
Appreciate your thoughts on why this does not compile?
typedef unsigned int uint32;
class TestObject
{
public:
TestObject()
: mValue(0)
{
}
uint32 GetValue() const
{
return mValue;
}
private:
uint32 mValue;
};
template <typename T>
TestObject& operator<<(TestObject& o, const T& t)
{
return o;
}
void TestObjectTest()
{
TestObject myTestObject;
uint32 newValue = 123;
const uint32 resultValue = (myTestObject << newValue).GetValue(); // This compiles for both visual studio 2013 and gcc.
const uint32 resultValue2 = (TestObject() << newValue).GetValue(); // Compiles using visual studio 2013, but does not compile using x86-64 gcc 6.2: "no match for 'operator<<' in 'TestObject() << newValue'
}
int main(void)
{
TestObjectTest();
return 0;
}
TestObject() yields a temporary TestObject. Since it is not a temporary you cannot bind it to a lvalue reference (except for MSVS's evil extension). If your operator does not need to modify the TestObject then simply changing it to take a const& is enough:
template <typename T>
const TestObject& operator<<(const TestObject& o, const T& t)
{
return o;
}
If you need to modify the value then you need to add another overload and take in a rvalue reference. That will bind to the temporary and allow you to modify it:
template <typename T>
TestObject& operator<<(TestObject&& o, const T& t)
{
return o;
}
Related
So guys, I have an abstract class, other class that stores an implementation from this class in the stack (I don't want heap allocations and I don't know other way to do it without making the caller explicitly declares the implementation) and another that stores a reference of this interface class. But, it seems that GCC don't store the implementation class in the stack and when the interface class is used probably the implementation class vtable is not found.
Basically, everything works fine when compiled with GCC 4.8.1 without optimizations, but when I try to use it, the program crashes and then returns 139.
I don't know why GCC 4 doesn't support it, while GCC 5 does, but I see that they generate different instructions.
Compiler Explorer: https://godbolt.org/z/Wfvj65
#include <cstdio>
#define FORCEINLINE inline __attribute__((always_inline))
class IFormatter
{
public:
virtual void Format(const void* InData) const = 0;
};
template<typename T>
class TFormatter :
public IFormatter
{
public:
TFormatter() = delete;
};
using Scalar = float;
// Implemented, fine.
struct RVector2
{
Scalar X;
Scalar Y;
};
// Not implemented, get error.
struct RVector3
{
Scalar X;
Scalar Y;
Scalar Z;
};
template<>
class TFormatter<RVector2> :
public IFormatter
{
public:
virtual void Format(const void*) const override
{
printf("[RVector2]\n");
}
};
template<typename T>
class TCustom
{
public:
FORCEINLINE TCustom(const T& InValue) :
Value(InValue),
Format(TFormatter<T>{})
{
}
FORCEINLINE const T* Data() const
{
return &Value;
}
FORCEINLINE const IFormatter& Formatter() const
{
return Format;
}
private:
const T& Value;
TFormatter<T> Format;
};
template<typename T>
FORCEINLINE TCustom<T> MakeCustom(const T& InValue)
{
return TCustom<T>{ InValue };
}
class RCustom
{
public:
FORCEINLINE RCustom(const void* InValue, const IFormatter& InFormatter) :
Data(InValue),
Formatter(InFormatter)
{
}
template<typename T>
FORCEINLINE RCustom(TCustom<T> const& InCustom) :
RCustom(InCustom.Data(), InCustom.Formatter())
{
}
FORCEINLINE const IFormatter& Get() const
{
return Formatter;
}
private:
const void* Data;
const IFormatter& Formatter;
};
int main()
{
const RVector2 Vector{};
const RCustom Custom = MakeCustom(Vector);
Custom.Get().Format(nullptr);
return 0;
}
As one of the comments said there is something weird going on with storing TCustom in the unrelated type RCustom. The implicit constructor RCustom(TCustom) threw me off.
The issue is quite subtle. If something works with -O0 but not with -Ofast (or -O2/-O3), most of the time something funny is happening with the memory. As Benny K said, in your case the issue is that RCustom only stores a reference to IFormatter:
class RCustom {
...
const IFormatter& Formatter; // Asking for problems
}
This is seems like an innocent &, but in fact this is dangerous. Because the validity of this member is dependent on the lifetime of an external object. There are a few possibilities to fix this. You could save a copy of the TFormatter in RCustom (instead of a reference):
template<typename T>
class RCustom {
...
const TFormatter<T> Formatter;
}
But this also means you have to give up the abstract interface IFormatter for the concrete one TFormatter<T>. To work with virtual methods in C++ you need a pointer, but using a raw-pointer will introduce the same memory problems as the references. So I suggest you use smart pointers:
class RCustom {
...
std::shared_ptr<const IFormatter> Formatter;
}
PS: to be precise about what's going wrong: In MakeCustom() you initialize a TCustom object which initializes and copies an instance of TFormatter. Next a reference to the instance of TFormatter in TCustom is saved in RCustom. Now this RCustom object is returned and the function MakeCustom() is cleaned up. In this cleaning process TCustom is destroyed, and so is the TFormatter-member. But the RCustom still retains a reference to this invalid memory. In C++ the difference between an & and no & is rather important.
Revisiting lifetime extension in C++, I found out that there are some patterns that break "decomposability" of C++ expressions. For example, the following two blocks are a valid C++ code:
class NonMovable {
public:
NonMovable(NonMovable&&) = delete;
NonMovable(const NonMovable&) = delete;
NonMovable();
int Value() const;
};
template <class T>
const T& identity(const T& x) {
return x;
}
template <class T>
class A {
public:
explicit A(const T& value) : value_(value) {}
const T& GetValue() const {
return value_;
}
private:
const T& value_;
};
Correct usage:
int main() {
int retcode = identity(
identity(/*tmp1*/ A(/*tmp2*/ NonMovable{}).GetValue())).Value();
// tmp1 and tmp2 end their lifetimes here:
// their full-expression is the whole previous line
return retcode;
}
But if we decompose the first expression in main, it becomes invalid:
int main() {
auto&& a_obj = /*tmp1*/ A(/*tmp2*/ NonMovable{});
// tmp2 lifetime ends here
// oops! dereferencing dangling reference:
int retcode = identity(
identity(a_obj.GetValue())).Value();
return retcode;
// tmp1 lifetime ends here
}
My question is:
Is it possible to disable the second kind of usage?
P.S.: I'm not really sure if the second main introduces UB, because I've tested it with clang -Wlifetime, and it doesn't complain. But I still believe it is UB. In real life I've came across a similar behaviour: the code broke, emmiting UBSan warnings and segfaults if I decomposed a single expression into two separate ones.
P.P.S.: those identitys don't really matter much, if I understand object lifetimes correctly (which I now doubt)
Your analysis is correct. Without lifetime extension, all temporaries are destroyed at the end of the "full expression", i.e. the ; at the end of the line. So when you say
int retcode = A(NonMovable{}).GetValue().Value();
(comments and identity calls removed for clarity) then everything is okay; the NonMovable object is still alive at the time you ask for its value.
On the other hand, when you say
auto&& a_obj = A(NonMovable{});
then the NonMovable is destroyed at the end of the line, and the A object will be holding a dangling reference. (As an aside, auto&& just lifetime-extends the temporary A here -- you may as well just use plain auto)
My question is: Is it possible to disable the second kind of usage?
Not really, at least as far as I know. You could add a deleted A(NonMovable&&) constructor, but this would also prevent "correct" usage as in the first example. The is exactly the same issue that occurs with std::string_view (and will occur with std::span in C++20) -- essentially, your A class has reference semantics, but is referring to a temporary which has been destroyed.
So by using collective mind, in the comments under the question we've managed to come up with the following implementation of A, which might be applicable to some use cases (but not std::span or std::string_view usage):
struct Dummy;
template <class T>
class A {
public:
explicit A(const T& value) : value_(value) {}
template <class TDummy = Dummy>
const T& GetValue() const& {
static_assert(!std::is_same_v<TDummy, Dummy>,
"Stop and think, you're doing something wrong!"
"And in any case, don't use std::move on this class!");
}
const T& GetValue() && {
return value_;
}
private:
const T& value_;
};
Now, if one tries to compile the following code, he will get a descriprive error message:
int main() {
auto&& a_obj = A(NonMovable{});
// will not compile:
int retcode = identity(
identity(a_obj.GetValue())).Value();
return retcode;
}
The reason is that decltype((a_obj)) == A<NonMovable>&, so it binds to the method that produces a compile time error.
It satisfies my use cases, but, sadly, this is not a universal solution -- it depends on what one wants from class A.
Consider following piece of code:
#include <functional>
template<class T>
class factory {
public:
factory(T &&t) : t_(std::forward<T>(t)) {}
private:
T &&t_;
};
template<class T>
factory<T> make_factory(T &&t) {
return factory<T>(std::forward<T>(t));
}
int main(){
int i = 3;
auto bar = make_factory(i); //now it will store int &
auto foo = make_factory(5); //now will store int &&
return 0;
}
This is of course simplification of code but shows my general idea - I am considering storing references to rvalues. As far as I know in the first case the deduced type will be int & so the factory will be valid until leaving of the scope (due to reference collapsing). My questions are
Is the foo object causing undefined behaviour?
If not, for how long is the stored rvalue reference valid (I mean, what's its scope)?
Are there any caveats that I am missing?
EDIT:
I thought this is enough but I see I have to clarify. I want to achieve something like this:
template<class T>
class factory {
public:
factory(T &&t) : t_(std::forward<T>(t)) {}
auto make() const & {
return wrap(t_);
}
auto make() && {
return wrap(/*what here, move(t_), forward<T>(t_) ?*/);
}
private:
T t_;//or maybe T&& here?
};
I do not want to copy the member unless I really have to. I would like to do something like forwarding through the factory class.
Generally do this:
template<class T>
class factory {
public:
factory(T &&t) : t_(std::forward<T>(t)) {}
private:
T t_; // could be a lvalue ref
};
and it just works. Really. Yep, that case too.
Rvalues should not outlive their enclosing statement; so your make factory should not return a struct containing an rvalue ref.
I have a struct with a std::map of pointers inside it. I'm trying to do the following:
template <class T>
struct Foo
{
std::map<std::string, T*> f;
T& operator[](std::string s)
{
return *f[s];
}
}
and then use it like this:
Foo<Bar> f;
f["key"] = new Bar();
but the way it's written, it crashes the program. I also tried like this:
T* operator[](std::string s)
{
return f[s];
}
but it doesnt compile. It says "lvalue required as left operand of assignment" on the f["key"] = new Bar() line.
I expected it to be easy since I'm trying to return a pointer and I'm storing a pointer. What is wrong with my code?
The correct way of doing this is:
T*& operator[](std::string s)
{
return f[s];
}
and call it like f["key"] = new Bar().
EDIT: You should start passing non-basic types by const reference where you can:
T*& operator[](const std::string& s)
How do I make a class in C++, when initialized, return a Boolean value when its name is invoked, but no explicit function call make, like ifstream. I want to be able to do this:
objdef anobj();
if(anobj){
//initialize check is true
}else{
//cannot use object right now
}
not just for initialization, but a check for its ability to be used.
The way istream does it is by providing an implicit conversion to void*
http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/
stream output and implicit void* cast operator function invocation
Update In reaction to the comments, the Safe Bool Idiom would be a far better solution to this: (code directly taken from that page)
class Testable {
bool ok_;
typedef void (Testable::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool_type() const {
return ok_==true ?
&Testable::this_type_does_not_support_comparisons : 0;
}
};
template <typename T>
bool operator!=(const Testable& lhs,const T& rhs) {
lhs.this_type_does_not_support_comparisons();
return false;
}
template <typename T>
bool operator==(const Testable& lhs,const T& rhs) {
lhs.this_type_does_not_support_comparisons();
return false;
}
The article by Bjorn Karlsson contains a reusable implementation for the Safe Bool Idiom
Old sample:
For enjoyment, I still show the straight forward implementation with operator void* overloading, for clarity and also to show the problem with that:
#include <iostream>
struct myclass
{
bool m_isOk;
myclass() : m_isOk(true) { }
operator void* () const { return (void*) (m_isOk? 0x1 : 0x0); }
};
myclass instance;
int main()
{
if (instance)
std::cout << "Ok" << std::endl;
// the trouble with this:
delete instance; // no compile error !
return 0;
}
This is best accomplished using the safe bool idiom.
You provide an implicit conversion to a member-function-pointer, which allows instances of the type to be used in conditions but not implicitly convertyed to bool.
You need a (default) constructor and an operator bool()().
class X {
public:
operator bool ()const{
//... return a boolean expression
}
};
usage:
X x; // note: no brackets!
if( x ) {
....
}
You'll want to create an operator bool function (or as boost does, an unspecified_bool_type that has certain improved properties I can't recall offhand). You may also want to create operator! (For some reason I seem to recall iostreams do this too).