Is the following code considered safe?
Foo& GetFoo()
{
static std::once_flag fooInitFlag;
static Foo f;
std::call_once(fooInitFlag, [&Foo]()
{
Foo.Init();
});
return std::ref(f);
}
Instead of this posted code:
Foo& GetFoo()
{
static std::once_flag fooInitFlag;
static Foo f;
std::call_once(fooInitFlag, [&Foo]()
{
Foo.Init();
});
return std::ref(f);
}
do this:
struct Initialized_foo
{
Foo item;
Initialized_foo() { item.Init(); }
};
auto get_foo()
-> Foo&
{
static Initialized_foo the_foo;
return the_foo.item;
}
It's not more safe, but it's simpler, and hence more safe against inadvertently introduced bugs.
Note that the standard guarantees a single initialization here, even in the context of multi-threading.
Better, ideally each Foo insteance should be properly initialized by the Foo constructor, not by an Init method. But that's not always possible to arrange.
You asked:
Is the following code considered safe?
The answer is yes.
Another implementation:
// Not exposed to the outside.
static Foo& getInitializedFoo();
{
static Foo f;
f.Init();
return f;
}
Foo& GetFoo()
{
static Foo& f = getInitializedFoo();
return f;
}
Related
I am wondering, after C++17, is there a way to check whether temporary materialization occurs?
For example, imagine we have a class Foo and we then do something like
Foo().someFunction()
in such a scenario Foo() is temporarily materialized to an xvalue. Can I prove (through code) that this indeed happens?
You can mark foo() with a non-const lvalue ref-qualifier:
struct Foo {
void foo() & { }
};
Foo make() { return Foo(); }
Foo & singleton() { static Foo t; return t; }
void bla() {
Foo t;
// "permanent" Foo work
t.foo();
singleton().foo();
// temporary Foo fail to compile
Foo().foo();
make().foo();
}
Now you get compiler error with temporaries: https://godbolt.org/z/1re8oEE43
It seems you can return an unnamed struct this way:
auto foo() {
struct {
int bar;
int square() {
return bar * bar;
}
} a { 7 };
return a;
}
Is there anyway to do this without the redundant variable name a, thus anonymously?
For starters C++ does not define anonymous structures. I think you mean an unnamed structure.
According ro the C++ Standard the return statement is defined like (8.6 Jump statements)
return expr-or-braced-init-listopt ;
So you may not use a declaration in the return statement. If so then you need prelimary to declare an object of the structure type that will be returned.
I have no idea what the point of this exercise is, so here is an answer that technically does what you ask for:
auto helper()
{
struct {
int x;
} a {0};
return a;
}
decltype(helper()) foo()
{
return {8};
}
https://godbolt.org/z/zA8C1V
The struct is unnamed.
foo does not return a named variable.
Of course this is straight up ridiculous - one would just name the struct instead of this decltype tomfoolery.
No, this is not possible.
The closest you can get is to use a functional-style cast to create a temporary, and use a C99-style scoped-initialiser; GCC allows this in C++ mode, as an extension:
#include <iostream>
#include <string>
auto foo() {
return (struct {
int bar;
int square() {
return bar * bar;
}
}) { 7 };
}
… but this is not portable (and will warn).
Without the braces around 7 the extension is not triggered, and you're back to standard code, in which it is illegal to define a type in a cast.
Instead of writing obtuse code, give your type a name and give your object a name. Your readers will thank you.
None of
struct {/*...*/} foo() { // Illegal
return {/*...*/};
}
auto foo() {
return struct { /*...*/ } { /*...*/ }; // Illegal
}
template <typename T = struct { /*...*/ }> // Illegal
T foo() {
return { /*...*/ };
}
are legal.
You have to, at least, have a named type, or a named instance.
Lambda allows to have neither, but you can only capture and define its operator():
auto foo() {
return [/*...*/](/*...*/) { /*...*/ }; // Legal
}
Returning anonymous struct
There is no such thing as anonymous struct in C++. That's enough to make it impossible.
There is a - limited - way of returning an object of anonymous type from a function: Returning a lambda.
auto make_square_function() {
return [bar = 7]() {
return bar * bar;
};
}
Lambdas are much more limited than general classes though. The members (captures) are encapsulated and cannot be named from the outside of the lambda and there are no member functions other than the function call overload.
Is there anyway to do this without the redundant variable name a
Only if you give the class a name:
struct Squarer {
int bar;
int square() {
return bar * bar;
}
};
auto foo() {
return Squarer{7};
}
Returning an instance of unnamed class is only possible by defining a variable.
Just for fun, another define-the-variable-in-another-function solution (taking inspiration from Max Langhof's answer)
auto foo ()
{
return []{ struct{int bar;} a {7}; return a; }();
}
No, because you need to return an instance of an object, in this case a.
The returned object has to exist somewhere in memory, you can't just return a class definition.
In your example, you don't return an anonymous struct, but you return an instance of that struct.
Consider the following piece of C++ code:
class Foo {
public:
int a;
};
class Bar {
public:
int w = 1;
bool are_foos_equal(Foo* f1, Foo* f2) { return f1->a * w == f2->a * w; }
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
Now, this doesn't compile because in the operator () of FooEqual I cannot invoke non-static are_foos_equal.
My question is: is it possible for fooset to use are_foos_equal somehow? I know that I could just make are_foos_equal static but the example code I gave is just so that I could state my problem which, unfortunately, occured in a much bigger project, and even if that means that the design is somewhat wrong, I'd like to rescue it by some hacks, if possible.
EDIT
I added a non-static member variable w to Bar to emphasize "non-staticness" of are_foos_equal.
Move are_foos_equal() outside of the class and make it a free function. It doesn't make sense that it should be a member of Bar. Example:
class Foo {
public:
int a;
};
bool are_foos_equal(Foo* f1, Foo* f2)
{return f1->a == f2->a;}
class Bar {
public:
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
You could maintain a reference to the parent Bar object in FooEqual:
Bar() : fooset{10, FooHash{}, FooEqual{*this}}
{}
struct FooEqual {
Bar& parent;
bool operator () (Foo* f1, Foo* f2) const {
return parent.are_foos_equal(f1, f2);
}
};
Because of how the constructors are declared in std::unordered_set you need to provide a bucket count, which is a bit unfortunate. You could get the default from a default-constructed std::unordered_set if you felt like it.
The correct option would definitely be to make are_foos_equal static. I would strongly suggest doing this instead of a hack. The larger the project, the cleaner it needs to be so that it doesn't devolve into an unmaintainable mess.
But if that is seriously not an option, I see a few other possibilities:
Create a Bar object on the fly inside FooEqual:
return Bar().are_foos_equal(f1, f2);
Have FooEqual store a static Bar object for this purpose:
bool operator() (Foo* f1, Foo* f2) const {
static Bar bar;
return bar.are_foos_equal(f1, f2);
}
Invoke Undefined Behaviour, invoke are_foos_equal on a null pointer and hope that it doesn't do anything bad. I strongly discourage this:
return static_cast<Bar*>(nullptr)->are_foos_equal(f1, f2);
Here it could be trivial, because are_foos_equal could be static, as it neither use not change anything in this
=> first way just declare are_foos_equal static.
Alternatively, if the called function cannot be static because it uses or changes it object, you will have to change FooEqual to contain a Bar object (or a pointer or reference to it) . Because C++ is not java: inner classes have no hidden pointer to an object of enclosing class.
=> second way add a reference to a Bar in FooEqual and set it at construction time:
struct FooEqual {
const Bar &bar;
FooEqual(const Bar& bar): bar(bar) {};
bool operator () (Foo* f1, Foo* f2) const {
return bar.are_foos_equal(f1, f2);
}
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.
}
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.