How to disallow temporaries

C++

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

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() {}")

Solution 2 - C++

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;
}

Solution 3 - C++

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

Solution 4 - C++

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.

Solution 5 - C++

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.

Solution 6 - C++

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&)’

Solution 7 - C++

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 );
}

Solution 8 - C++

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).

Solution 9 - C++

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.

Solution 10 - C++

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMartin C. MartinView Question on Stackoverflow
Solution 1 - C++ecatmurView Answer on Stackoverflow
Solution 2 - C++user1773602View Answer on Stackoverflow
Solution 3 - C++dchhetriView Answer on Stackoverflow
Solution 4 - C++Johannes Schaub - litbView Answer on Stackoverflow
Solution 5 - C++KazView Answer on Stackoverflow
Solution 6 - C++Alok SaveView Answer on Stackoverflow
Solution 7 - C++Cheers and hth. - AlfView Answer on Stackoverflow
Solution 8 - C++amaureaView Answer on Stackoverflow
Solution 9 - C++Daniel FreyView Answer on Stackoverflow
Solution 10 - C++stefan.galView Answer on Stackoverflow