Can I avoid accidental construction of a temporary? [duplicate] - c++

For a class Foo, is there a way to disallow constructing it without giving it a name?
For example:
Foo("hi");
And only allow it if you give it a name, like the following?
Foo my_foo("hi");
The lifetime of the first one is just the statement, and the second one is the enclosing block. In my use case, Foo is measuring the time between constructor and destructor. Since I never refer to the local variable, I often forget to put it in, and accidentally change the lifetime. I'd like to get a compile time error instead.

Another macro-based solution:
#define Foo class Foo
The statement Foo("hi"); expands to class Foo("hi");, which is ill-formed; but Foo a("hi") expands to class Foo a("hi"), which is correct.
This has the advantage that it is both source- and binary-compatible with existing (correct) code. (This claim is not entirely correct - please see Johannes Schaub's Comment and ensuing discussion below: "How can you know that it is source compatible with existing code? His friend includes his header and has void f() { int Foo = 0; } which previously compiled fine and now miscompiles! Also, every line that defines a member function of class Foo fails: void class Foo::bar() {}")

How about a little hack
class Foo
{
public:
Foo (const char*) {}
};
void Foo (float);
int main ()
{
Foo ("hello"); // error
class Foo a("hi"); // OK
return 1;
}

Make the constructor private but give the class a create method.

This one doesn't result in a compiler error, but a runtime error. Instead of measuring a wrong time, you get an exception which may be acceptable too.
Any constructor you want to guard needs a default argument on which set(guard) is called.
struct Guard {
Guard()
:guardflagp()
{ }
~Guard() {
assert(guardflagp && "Forgot to call guard?");
*guardflagp = 0;
}
void *set(Guard const *&guardflag) {
if(guardflagp) {
*guardflagp = 0;
}
guardflagp = &guardflag;
*guardflagp = this;
}
private:
Guard const **guardflagp;
};
class Foo {
public:
Foo(const char *arg1, Guard &&g = Guard())
:guard()
{ g.set(guard); }
~Foo() {
assert(!guard && "A Foo object cannot be temporary!");
}
private:
mutable Guard const *guard;
};
The characteristics are:
Foo f() {
// OK (no temporary)
Foo f1("hello");
// may throw (may introduce a temporary on behalf of the compiler)
Foo f2 = "hello";
// may throw (introduces a temporary that may be optimized away
Foo f3 = Foo("hello");
// OK (no temporary)
Foo f4{"hello"};
// OK (no temporary)
Foo f = { "hello" };
// always throws
Foo("hello");
// OK (normal copy)
return f;
// may throw (may introduce a temporary on behalf of the compiler)
return "hello";
// OK (initialized temporary lives longer than its initializers)
return { "hello" };
}
int main() {
// OK (it's f that created the temporary in its body)
f();
// OK (normal copy)
Foo g1(f());
// OK (normal copy)
Foo g2 = f();
}
The case of f2, f3 and the return of "hello" may not be wanted. To prevent throwing, you can allow the source of a copy to be a temporary, by resetting the guard to now guard us instead of the source of the copy. Now you also see why we used the pointers above - it allows us to be flexible.
class Foo {
public:
Foo(const char *arg1, Guard &&g = Guard())
:guard()
{ g.set(guard); }
Foo(Foo &&other)
:guard(other.guard)
{
if(guard) {
guard->set(guard);
}
}
Foo(const Foo& other)
:guard(other.guard)
{
if(guard) {
guard->set(guard);
}
}
~Foo() {
assert(!guard && "A Foo object cannot be temporary!");
}
private:
mutable Guard const *guard;
};
The characteristics for f2, f3 and for return "hello" are now always // OK.

A few years ago I wrote a patch for the GNU C++ compiler which adds a new warning option for that situation. This is tracked in a Bugzilla item.
Unfortunately, GCC Bugzilla is a burial ground where well-considered patch-included feature suggestions go to die. :)
This was motivated by the desire to catch exactly the sort of bugs that are the subject of this question in code which uses local objects as gadgets for locking and unlocking, measuring execution time and so forth.

As is, with your implementation, you cannot do this, but you can use this rule to your advantage:
Temporary objects cannot be bound to non-const references
You can move the code from the class to an freestanding function which takes a non-const reference parameter. If you do so, You will get a compiler error if an temporary tries to bind to the non-const reference.
Code Sample
class Foo
{
public:
Foo(const char* ){}
friend void InitMethod(Foo& obj);
};
void InitMethod(Foo& obj){}
int main()
{
Foo myVar("InitMe");
InitMethod(myVar); //Works
InitMethod("InitMe"); //Does not work
return 0;
}
Output
prog.cpp: In function ‘int main()’:
prog.cpp:13: error: invalid initialization of non-const reference of type ‘Foo&’ from a temporary of type ‘const char*’
prog.cpp:7: error: in passing argument 1 of ‘void InitMethod(Foo&)’

Simply don't have a default constructor, and do require a reference to an instance in every constructor.
#include <iostream>
using namespace std;
enum SelfRef { selfRef };
struct S
{
S( SelfRef, S const & ) {}
};
int main()
{
S a( selfRef, a );
}

No, I'm afraid this isn't possible. But you could get the same effect by creating a macro.
#define FOO(x) Foo _foo(x)
With this in place, you can just write FOO(x) instead of Foo my_foo(x).

Since the primary goal is to prevent bugs, consider this:
struct Foo
{
Foo( const char* ) { /* ... */ }
};
enum { Foo };
int main()
{
struct Foo foo( "hi" ); // OK
struct Foo( "hi" ); // fail
Foo foo( "hi" ); // fail
Foo( "hi" ); // fail
}
That way you can't forget to name the variable and you can't forget to write struct. Verbose, but safe.

Declare one-parametric constructor as explicit and nobody will ever create an object of that class unintentionally.
For example
class Foo
{
public:
explicit Foo(const char*);
};
void fun(const Foo&);
can only be used this way
void g() {
Foo a("text");
fun(a);
}
but never this way (through a temporary on the stack)
void g() {
fun("text");
}
See also: Alexandrescu, C++ Coding Standards, Item 40.

Related

Instance of Most Vexing Parse with std::string and char*

This is a follow-up to my previous question: C++ compile error constructing object with rvalue std::string from which I learned about the Most Vexing Parse.
I understand now the gist of the problem, however there's one leftover item of syntax I still don't quite understand, which I'd like to ask as a standalone question, since the discussions on the previous post were getting quite long.
Given this code:
#include <iostream>
#include <string>
class Foo
{
public:
Foo(double d)
: mD(d)
{
}
Foo(const std::string& str)
{
try
{
mD = std::stod(str);
}
catch (...)
{
throw;
}
}
Foo(const Foo& other)
: mD(other.mD)
{
}
virtual ~Foo() {}
protected:
double mD;
};
class Bar
{
public:
Bar(const Foo& a, const Foo& b)
: mA(a)
, mB(b)
{
}
virtual ~Bar() {}
protected:
Foo mA;
Foo mB;
};
int main(int argc, char* argv[])
{
if (argc < 3) { return 0; }
Foo a(std::string(argv[1]));
Foo b(std::string(argv[2]));
Bar wtf(a, b);
}
I understand, now, that the line Foo a(std::string(argv[1])); can be interpreted as either:
(1) Create a Foo named a with an anonymous std::string that is created with a char*. (My desired interpretation)
or
(2) A declaration (not definition) for a function named a that takes a std::string*.
From answers to the original question, I learned that functions could be declared within the scope of another function. That was new to me, but seems within reason, I can buy it.
What I can't wrap my head around, though, is the interpretation of std::string(argv[1]) as a std::string*.
argv[1] is a char*, so I still don't see why the line isn't interpreted as an anonymous std::string being constructed with a char*. After all, I've used code analogous to the following hundreds of times without ever scrutinizing whether this would result in anything other than the construction of a std::string with its char* constructor:
#include <iostream>
int main()
{
char* pFoo[] = {"foo"};
std::string str(pFoo[0]);
std::cout << str << std::endl;
return 0;
}
I'm on the cusp of understanding the most vexing parse problem; if someone could further explain this last niggling part, that might help push me over the edge.
Thank you.
Foo a(std::string(argv[1]));
declares a function named a which returns Foo and has one parameter (named argv) of type std::string[1]. Since array function parameters are always replaced with pointer parameters, the actual type of the function parameter becomes std::string*.

object *operator<<(object* one, type& two);

Original XY Problem Question
I'm in the situation where I need to use the object& operator<<(object& one, type& two); operator overload, with the tweak of using pointers instead of references as below
object *operator<<(object* one, type& two);
The reason is my copy constructors and assignment operators are deleted because I am implementing an object similar to cout and cin. What's a neat hack to do this? I might go with windows API style code where I would define a class pObject; which is a class wrapper for a pointer to the object, but I want to know if there's a more elegant way.
More Generic
I have the following code where T and T' and distinct data types:
// foobar.h
namespace foo {
class bar;
extern foo::bar bExt;
}
foo::bar *operator<<(foo::bar *, T&);
namespace foo {
class bar {
public:
static foo::bar *GetBar() { return new foo::bar; }
void doSomething(T &t) {/* uses member variable mvar.*/}
private:
T' mvar;
friend foo::bar *::operator<<(foo::bar *, T &);
bar() {/*initialize mvar appropriately*/} // default constructor
bar(foo::bar const&) = delete;
void operator=(foo::bar const&) = delete;
};
}
//foobar.cpp
#include "foobar.h"
foo::bar *foo::bExt = GetBar();
foo::bar *operator<<(foo::bar *b, T&)
{
b->doSomething(T);
return b;
}
// main.cpp
#include "foobar.h"
int main()
{
T x = /*something*/;
foo::bExt << x;
}
What I am hoping for is that the user will not be able to create an instance of bar or modify the foo::bExt, which is not a constant because doSomething() modifies it. Finally, I need a way to do it all while still allowing for the operator overload object& operator<<(object& one, type& two); which has been incorrectly used above.
Further Clarification
The code posted below this paragraph will not compile because the copy constructor and assignment operator have been deleted. However, this is the exact format my code requires because one way or the other the extern variable foo::bExt needs to be defined via some complicated constructor procedure and then used as an argument to the overload operator similar to the appearance and use of std::cout. The quick workaround is to to define a extern foo::bar * object, as has been stated in the code above this paragraph, and use the pointer as the argument to the operator. A quick fix is is to dereference the now pointer extern object *foo::bExt every time the operator<< is invoked with it as argument, but no one does *std::cout << 1; so nor should they *foo::bExt << 1;. It seems cumbersome and inelegant, and at least warrants an investigation for an alternative. Hence my question. Don't just take my word for it, try the below code with
g++ -std=c++11 <name>.cpp -o <name>
#include <iostream>
namespace foo
{
class bar;
extern foo::bar bExt;
}
foo::bar &operator<<(foo::bar& ,int&);
namespace foo
{
class bar
{
public:
static foo::bar GetBar()
{
static foo::bar temp;
return temp;
}
void print() {std::cout << v << std::endl;}
private:
int v;
bar() : v(1965) {};
friend foo::bar &::operator<<(foo::bar &, int&);
/* Commenting out the below copy constructor and
* assignment operator allows the code to compile.
*/
bar(foo::bar const&) = delete;
void operator=(foo::bar const&) = delete;
};
foo::bar bExt = foo::bar::GetBar();
}
foo::bar &operator<<(foo::bar &b, int &i)
{
b.v += i;
return b;
}
int main()
{
int i = 50;
foo::bExt << i;
foo::bExt.print();
}
As has been pointed out (no pun intended) in comments on your question, there is nothing wrong with using references; however, it appears that you don't understand why, so I will explain it.
References contain built-in constant pointers. This means that when you pass a reference to an object, neither the copy constructor nor the assignment operator are called on your object; rather, it is the reference's internal pointer that is copied over, and there is still only one copy of the object itself. For that reason, you can still use references to the object, even if the copy constructor and/or assignment operator are deleted.
I hope this helps you understand how references work.
EDIT: actual full solution
Here is an actual solution based on the second code block given in the question:
#include <iostream>
namespace foo
{
class bar;
extern foo::bar& bExt;
}
foo::bar &operator<<(foo::bar& ,int&);
namespace foo
{
class bar
{
public:
static foo::bar* GetBar()
{
return new foo::bar();
}
void print() {std::cout << v << std::endl;}
private:
int v;
bar() : v(1965) {};
friend foo::bar&::operator<<(foo::bar&, int&);
/* Commenting out the below copy constructor and
* assignment operator allows the code to compile.
*/
bar(foo::bar const&) = delete;
void operator=(foo::bar const&) = delete;
};
foo::bar& bExt = *foo::bar::GetBar();
}
foo::bar &operator<<(foo::bar &b, int &i)
{
b.v += i;
return b;
}
int main()
{
int i = 50;
foo::bExt << i;
foo::bExt.print();
}
Hopefully this helps.
Turns out the following overload does the trick:
object *& operator<<(object *& one, type& two);

Can a C++ lambda constructor argument capture the constructed variable?

The following compiles. But is there ever any sort of dangling reference issue?
class Foo {
Foo(std::function<void(int)> fn) { /* etc */ }
}
void f(int i, Foo& foo) { /* stuff with i and foo */ }
Foo foo([&foo](int i){f(i, foo);});
Seems to work. (The real lambda is of course more complicated.)
But is there ever any sort of dangling reference issue?
That depends entirely on what you're doing with Foo. Here's an example that would have dangling reference issues:
struct Foo {
Foo() = default;
Foo(std::function<void(int)> fn) : fn(fn) { }
std::function<void(int)> fn;
}
Foo outer;
{
Foo inner([&inner](int i){f(i, inner);});
outer = inner;
}
outer.fn(42); // still has reference to inner, which has now been destroyed
The lambda expression [&foo](int i){f(i, foo);} will lead compiler to generate a closure class something like this (but not totally correct) :
class _lambda
{
Foo& mFoo; // foo is captured by reference
public:
_lambda(Foo& foo) : mFoo(foo) {}
void operator()(int i) const
{
f(i, mFoo);
}
};
Therefore, the declaration Foo foo([&foo](int i){f(i, foo);}); is treated as Foo foo(_lambda(foo));. Capturing foo itself when constructing does not has problem in this situation because only its address is required here (References are usually implemented via pointers).
The type std::function<void(int)> will internally copy construct this lambda type, which means that Foo's constructor argument fn holds a copy of _lambda object (that holds a reference (i.e., mFoo) to your foo).
These implies that dangling reference issue may arise in some situations, for example:
std::vector<std::function<void(int)>> vfn; // assume vfn live longer than foo
class Foo {
Foo(std::function<void(int)> fn) { vfn.push_back(fn); }
}
void f(int i, Foo& foo) { /* stuff with i and foo */ }
Foo foo([&foo](int i){f(i, foo);});
....
void ff()
{
// assume foo is destroyed already,
vfn.pop_back()(0); // then this passes a dangling reference to f.
}

c++ object reference corrupted when running in Visual Studio debug mode

I have two classes, Foo and Bar. Bar maintains a reference to Foo, and has methods that call methods in Foo to change its state. The code is shown below.
class Foo
{
private:
double m_value;
public:
void setValue(double value) {
this->m_value = value;
};
double getValue() {
return this->m_value;
};
};
class Bar
{
private:
Foo& m_foo;
public:
Bar() : m_foo(Foo()) {
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
The problem arises when I try to access the value of foo after setting it, as below:
Bar bar;
bar.setFooValue(10000.0);
double value = bar.getFooValue();
std::cout << "Foo value is: " << value << std::endl;
Which outputs Foo value is -9.25596e+061. It appears the memory has become corrupt - why? I understand that not storing m_foo as a reference (i.e. using Foo m_foo;) will fix the issue, however I don't understand why this is either.
More puzzling still is that the code above works as desired when running in release mode.
I am using Visual Studio 2010 to compile.
Many thanks in advance!
Few compilers does report error for constructor Bar(). I have got the below error while compiling itself,
In constructor 'Bar::Bar()': invalid initialization of non-const
reference of type 'Foo&' from a temporary of type 'Foo' compilation
terminated due to -Wfatal-errors
Bar() : m_foo(Foo()) { };
In the constructor Bar, Foo() returns an object that is created in the stack and its life time ends when the constructor returns. Hence its life time is temporary and this will lead to accessing undefined memory or dangling references.
Solution 1: Use the Foo object as is without any reference
class Bar
{
private:
Foo m_foo;
public:
Bar(){
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
Solution 2: Pass Foo object as parameter to the Bar constructor and this will remain valid till the scope of main.
class Bar
{
private:
Foo &m_foo;
public:
Bar(Foo &x) : m_foo(x) {
};
void setFooValue(double value) {
m_foo.setValue(value);
};
double getFooValue() {
return m_foo.getValue();
};
};
int main()
{
Foo x;
Bar bar(x);
bar.setFooValue(10000.0);
double value = bar.getFooValue();
std::cout << "Foo value is: " << value << std::endl;
}
When you create Bar
Bar() : m_foo(Foo()) {
};
You provide reference to newly created foo instance that will go out of scope and will be deleted right after being assigned to m_foo. And this is actually VS c compiler flaw, since g++ would give you and error for such code, that you can see here.
http://liveworkspace.org/code/3kW04t$218
Bar() : m_foo(Foo())
You are trying to initialize lvalue-reference from temporary. You shouldn't do such things. After last bracket - object will be destroyed and you will have dangling reference.
Really, there is non-standard extension in MSVC, that allows bind temporary object to reference. For example gcc give error for such cases test here You can check this answer rvalue to lvalue conversion Visual Studio too.

How to disallow temporaries

For a class Foo, is there a way to disallow constructing it without giving it a name?
For example:
Foo("hi");
And only allow it if you give it a name, like the following?
Foo my_foo("hi");
The lifetime of the first one is just the statement, and the second one is the enclosing block. In my use case, Foo is measuring the time between constructor and destructor. Since I never refer to the local variable, I often forget to put it in, and accidentally change the lifetime. I'd like to get a compile time error instead.
Another macro-based solution:
#define Foo class Foo
The statement Foo("hi"); expands to class Foo("hi");, which is ill-formed; but Foo a("hi") expands to class Foo a("hi"), which is correct.
This has the advantage that it is both source- and binary-compatible with existing (correct) code. (This claim is not entirely correct - please see Johannes Schaub's Comment and ensuing discussion below: "How can you know that it is source compatible with existing code? His friend includes his header and has void f() { int Foo = 0; } which previously compiled fine and now miscompiles! Also, every line that defines a member function of class Foo fails: void class Foo::bar() {}")
How about a little hack
class Foo
{
public:
Foo (const char*) {}
};
void Foo (float);
int main ()
{
Foo ("hello"); // error
class Foo a("hi"); // OK
return 1;
}
Make the constructor private but give the class a create method.
This one doesn't result in a compiler error, but a runtime error. Instead of measuring a wrong time, you get an exception which may be acceptable too.
Any constructor you want to guard needs a default argument on which set(guard) is called.
struct Guard {
Guard()
:guardflagp()
{ }
~Guard() {
assert(guardflagp && "Forgot to call guard?");
*guardflagp = 0;
}
void *set(Guard const *&guardflag) {
if(guardflagp) {
*guardflagp = 0;
}
guardflagp = &guardflag;
*guardflagp = this;
}
private:
Guard const **guardflagp;
};
class Foo {
public:
Foo(const char *arg1, Guard &&g = Guard())
:guard()
{ g.set(guard); }
~Foo() {
assert(!guard && "A Foo object cannot be temporary!");
}
private:
mutable Guard const *guard;
};
The characteristics are:
Foo f() {
// OK (no temporary)
Foo f1("hello");
// may throw (may introduce a temporary on behalf of the compiler)
Foo f2 = "hello";
// may throw (introduces a temporary that may be optimized away
Foo f3 = Foo("hello");
// OK (no temporary)
Foo f4{"hello"};
// OK (no temporary)
Foo f = { "hello" };
// always throws
Foo("hello");
// OK (normal copy)
return f;
// may throw (may introduce a temporary on behalf of the compiler)
return "hello";
// OK (initialized temporary lives longer than its initializers)
return { "hello" };
}
int main() {
// OK (it's f that created the temporary in its body)
f();
// OK (normal copy)
Foo g1(f());
// OK (normal copy)
Foo g2 = f();
}
The case of f2, f3 and the return of "hello" may not be wanted. To prevent throwing, you can allow the source of a copy to be a temporary, by resetting the guard to now guard us instead of the source of the copy. Now you also see why we used the pointers above - it allows us to be flexible.
class Foo {
public:
Foo(const char *arg1, Guard &&g = Guard())
:guard()
{ g.set(guard); }
Foo(Foo &&other)
:guard(other.guard)
{
if(guard) {
guard->set(guard);
}
}
Foo(const Foo& other)
:guard(other.guard)
{
if(guard) {
guard->set(guard);
}
}
~Foo() {
assert(!guard && "A Foo object cannot be temporary!");
}
private:
mutable Guard const *guard;
};
The characteristics for f2, f3 and for return "hello" are now always // OK.
A few years ago I wrote a patch for the GNU C++ compiler which adds a new warning option for that situation. This is tracked in a Bugzilla item.
Unfortunately, GCC Bugzilla is a burial ground where well-considered patch-included feature suggestions go to die. :)
This was motivated by the desire to catch exactly the sort of bugs that are the subject of this question in code which uses local objects as gadgets for locking and unlocking, measuring execution time and so forth.
As is, with your implementation, you cannot do this, but you can use this rule to your advantage:
Temporary objects cannot be bound to non-const references
You can move the code from the class to an freestanding function which takes a non-const reference parameter. If you do so, You will get a compiler error if an temporary tries to bind to the non-const reference.
Code Sample
class Foo
{
public:
Foo(const char* ){}
friend void InitMethod(Foo& obj);
};
void InitMethod(Foo& obj){}
int main()
{
Foo myVar("InitMe");
InitMethod(myVar); //Works
InitMethod("InitMe"); //Does not work
return 0;
}
Output
prog.cpp: In function ‘int main()’:
prog.cpp:13: error: invalid initialization of non-const reference of type ‘Foo&’ from a temporary of type ‘const char*’
prog.cpp:7: error: in passing argument 1 of ‘void InitMethod(Foo&)’
Simply don't have a default constructor, and do require a reference to an instance in every constructor.
#include <iostream>
using namespace std;
enum SelfRef { selfRef };
struct S
{
S( SelfRef, S const & ) {}
};
int main()
{
S a( selfRef, a );
}
No, I'm afraid this isn't possible. But you could get the same effect by creating a macro.
#define FOO(x) Foo _foo(x)
With this in place, you can just write FOO(x) instead of Foo my_foo(x).
Since the primary goal is to prevent bugs, consider this:
struct Foo
{
Foo( const char* ) { /* ... */ }
};
enum { Foo };
int main()
{
struct Foo foo( "hi" ); // OK
struct Foo( "hi" ); // fail
Foo foo( "hi" ); // fail
Foo( "hi" ); // fail
}
That way you can't forget to name the variable and you can't forget to write struct. Verbose, but safe.
Declare one-parametric constructor as explicit and nobody will ever create an object of that class unintentionally.
For example
class Foo
{
public:
explicit Foo(const char*);
};
void fun(const Foo&);
can only be used this way
void g() {
Foo a("text");
fun(a);
}
but never this way (through a temporary on the stack)
void g() {
fun("text");
}
See also: Alexandrescu, C++ Coding Standards, Item 40.