What I want to do can be summarized into the following code:
struct A{};
struct B{
A& a;
B(A& a) noexcept : a(a){}
int operator()(int) {}
};
int main(){
A a;
B(a)(2);
}
And my compiler (g++ 6) rejected the code complaining that a shadows a parameter. However, if I try to explicitly call operator(), it works as expected.
It seems that g++ will ignore the parentheses and see the statement as a declaration.
Is this the specified or expected behavior?
This is one of those icky parsing rules which catches you every now and again. As you suggest, B(a)(2); is actually equivalent to B a(2);, so your code tries to initialize a B with an int.
To fix this, you can use C++11's uniform initialization:
B{a}(2);
Related
Using clang++ version 11 and C++ 17 with the compiler flag -Wall, clang will normally complain if you use a variable before it is initialized. However, it does not detect the following case:
struct Bar
{
bool b1;
};
class Foo {
public:
Foo()
: b2(Bar{b2}.b1) // We are using b2 here before it is initialized, but clang doesn't complain
{ }
bool b2;
};
This is the simplest example that I can create. It seems to only happen when initializing a member variable in the constructor (b2 in this case) with a member variable (b1) of an object (Bar). Does anyone know why clang fails to detect the problem here?
I recognize that this is a contrived example, but it actually caused a problem for me and I'd like to understand it.
It is not possible to detect if you used a member variable before it is initialized in the general case. Doing so for general programs violates Rice's theorem.
Compilers do not try.
Instead, they have some simple and cheap heuristics that catch common cases.
You cannot rely on your compiler to detect every case where you use uninitialized variables.
In this particular case, you are passing b2 to another class prior to initialization, but only using it to initialize a temporary variable. That is then used to initialize the variable that was originally initialized.
If that is your simplest case, clang is doing a pretty good job. Compilers tend to be worse at this when you use a variable as part of its own initialization statement.
Here is an even simpler case:
class Foo {
public:
Foo()
: b2((bool const&)b2) // We are using b2 here before it is initialized, but clang doesn't complain
{ }
bool b2;
};
another case:
struct Bob {
bool b;
operator bool() const{ return b; }
};
class Foo {
public:
Foo()
: b2(Bob{b2}) // We are using b2 here before it is initialized, but clang doesn't complain
{ }
bool b2;
};
another
Bob bob = {Bob{bob.b}.b};
I can go on.
Clang does not claim to detect all uninitialized variable uses. So it failing to detect one is not a "bug". Rather, getting them to detect another uninitialized case is a new feature.
Say, I have
struct Foo
{
char a;
char b;
};
void bar(Foo foo);
What's the most succinct way to initialize a struct and pass it to the function? Ideally I would like to write something like
bar(Foo = {'a','b'});
What if Foo was a union?
UPD: My sincere apologies, the question was supposed to be in relation to C++03 only. Also, in this particular case, going away from POD is to be avoided (the code is for embedded system, ergo shorter bytecode is sought after). vonbrand, thanks for the C++11 answer.
In C++ 11 you can write:
bar({'a', 'b'});
or:
bar(Foo{'a', 'b'});
(see Stroustup's C++11 FAQ).
g++-4.8.2 accepts this without complaints only if you give it -std=c++11, clang++-3.3 gives an error unless -std=c++11
You could add a constructor to your struct. e.g.
struct Foo
{
Foo(char a, char b) : a(a), b(b) {}
char a;
char b;
};
Then you could call your function
bar(Foo('a', 'b'));
If it was a union, you could have different constructors for the different types of the union.
Consider the following pair of mutually referencing types:
struct A;
struct B { A& a; };
struct A { B& b; };
This can be initialized with aggregate initialization in GCC, Clang, Intel, MSVC, but not SunPro which insists that user-defined ctors are required.
struct {A first; B second;} pair = {pair.second, pair.first};
Is this initialization legal?
slightly more elaborate demo: http://ideone.com/P4XFw
Now, heeding Sun's warning, what about classes with user-defined constructors? The following works in GCC, clang, Intel, SunPro, and MSVC, but is it legal?
struct A;
struct B { A& ref; B(A& a) : ref(a) {} };
struct A { B& ref; A(B& b) : ref(b) {} };
struct {B first; A second;} pair = {pair.second, pair.first};
demo: http://ideone.com/QQEpA
And finally, what if the container is not trivial either, e.g. (works in G++, Intel, Clang (with warnings), but not MSVC ("pair" unknown in initializer) or SunPro ("pair is not a structure")
std::pair<A, B> pair(pair.second, pair.first);
From what I can see, §3.8[basic.life]/6 forbids access to a non-static data member before lifetime begins, but is lvalue evaluation of pair.second "access" to second? If it is, then are all three initializations illegal? Also, §8.3.2[dcl.ref]/5 says "reference shall be initialized to refer to a valid object" which probably makes all three illegal as well, but perhaps I'm missing something and the compilers accept this for a reason.
PS: I realize these classes are not practical in any way, hence the language-lawyer tag. Related and marginally more practical old discussion here: Circular reference in C++ without pointers
This one was warping my mind at first but I think I got it now. As per 12.6.2.5 of 1998 Standard, C++ guarantees that data members are initialized in the order they are declared in the class, and that the constructor body is executed after all members have been initialized. This means that the expression
struct A;
struct B { A& a; };
struct A { B& b; };
struct {A first; B second;} pair = {pair.second, pair.first};
makes sense since pair is an auto (local, stack) variable, so its relative address and address of members are known to the compiler, AND there are no constructors for first and second.
Why the two conditions mean the code above makes sense: when first, of type A, is constructed (before any other data member of pair), first's data member b is set to reference pair.second, the address of which is known to the compiler because it is a stack variable (space already exists for it in the program, AFAIU). Note that pair.second as an object, ie memory segment, has not been initialized (contains garbage), but that doesn't change the fact that the address of that garbage is known at compile time and can be used to set references. Since A has no constructor, it can't attempt to do anything with b, so behavior is well defined. Once first has been initialized, it is the turn of second, and same: its data member a references pair.first, which is of type A, and pair.first address is known by compiler.
If the addresses were not known by compiler (say because using heap memory via new operator), there should be compile error, or if not, undefined behavior. Though judicious use of the placement new operator might allow it to work, since then again the addresses of both first and second could be known by the time first is initialized.
Now for the variation:
struct A;
struct B { A& ref; B(A& a) : ref(a) {} };
struct A { B& ref; A(B& b) : ref(b) {} };
struct {B first; A second;} pair = {pair.second, pair.first};
The only difference from first code example is that B constructor is explicitly defined, but the assembly code is surely identical as there is no code in the constructor bodies. So if first code sample works, the second should too.
HOWEVER, if there is code in the constructor body of B, which is getting a reference to something (pair.second) that hasn't been initialized yet (but for which address is defined and known), and that code uses a, well clearly you're looking for trouble. If you're lucky you'll get a crash, but writing to a will probably fail silently as the values get later overwritten when A constructor is eventually called. of
From compiler point of view references are nothing else but const pointers. Rewrite your example with pointers and it becomes clear how and why it works:
struct A;
struct B { A* a; };
struct A { B* b; };
struct {A first; B second;} pair = {&(pair.second), &(pair.first)}; //parentheses for clarity
As Schollii wrote: memory is allocated beforehand, thus addressable. There is no access nor evaluation because of references/pointers. That's merely taking addresses of "second" and "first", simple pointer arithmetics.
I could rant about how using references in any place other than operator is language abuse, but I think this example highlights the issue well enough :)
(From now on I write all the ctors manually. Your compiler may or may not do this automagically for you.)
Try using new:
struct A;
struct B { A& a; B(A& arg):a(arg){;} };
struct A { B& b; A(B& arg):b(arg){;} };
typedef struct PAIR{A first; B second; PAIR(B& argB, A& argA):first(argB),second(argA){;}} *PPAIR, *const CPPAIR;
PPAIR pPair = NULL;// just to clean garbage or 0xCDCD
pPair = new PAIR(pPair->second, pPair->first);
Now it depends on order of execution. If assignment is made last (after ctor) the second.p will point to 0x0000 and first.ref to e.g. 0x0004.
Actually, http://codepad.org/yp911ug6 here it's the ctors which are run last (makes most sense!), therefore everything works (even though it appears it shouldn't).
Can't speak about templates, though.
But your question was "Is that legal?". No law forbids it.
Will it work? Well, I don't trust compiler makers enough to make any statements about that.
I have a custom class that I want to behave like a built-in type.
However I have noticed that you can initialise a const variable of that class without providing an initial value. My class currently has an empty default constructor.
Here is a comparison of int and my class foo:
int a; // Valid
int a = 1; // Valid
const int a = 1; // Valid
const int a; // Error
foo a; // Valid
foo a = 1; // Valid
const foo a = 1; // Valid
const foo a; // Should cause an error, but it compiles
As you can see I need to prevent
const foo a;
from compiling.
Any ideas from C++ gurus?
It compiles only if it has a default constructor, and it compiles because it has it, which means that it is initialized. If you don't want that line to compile, just disable the default constructor (will also make foo a; an error as an unwanted side effect). Without a definition of foo or what you want to do, this is as far as I can get.
I don't think there is any way of achieving what you want (i.e. allow the non-const variable to be default initialized, while having the const version fail compilation and allowing the other use cases --that require providing constructors)
The rules of C++ simply say that default-initialization (e.g. new T;) and value-initialization (e.g. new T();) are the same for objects of class type, but not for objects of fundamental type.
There's nothing you can do to "override" this distinction. It's a fundamental part of the grammar. If your class is value-initializable, then it is also default-initializable.
There is a sort-of exception for classes without any user-defined constructors: In that case, initialization of members is done recursively (so if you default-init the object, it tries to default-init all members), and this will fail if any of the class members are themselves fundamental, or again of this nature.
For example, consider the following two classes:
struct Foo { int a; int b; };
struct Goo { int a; int b; Goo(){} };
//const Foo x; // error
const Goo y; // OK
The implicit constructor for Foo is rejected because it doesn't initialize the fundamental members. However, y is happily default-initialized, and y.a and y.b are now "intentionally left blank".
But unless your class doesn't have any user-defined constructors, this information won't help you. You cannot "forward" the initialization type to a member (like Foo() : INIT_SAME_AS_SELF(a), b() { }).
I want to initialize constant in child-class, instead of base class. And use it to get rid of dynamic memory allocation (I know array sizes already, and there will be a few child-classes with different constants).
So I try:
class A {
public:
const int x;
A() : x(0) {}
A(int x) : x(x) {}
void f() {
double y[this->x];
}
};
class B : A {
B() : A(2) {}
};
Pretty simple, but compiler says:
error C2057: expected constant expression
How can I say to compiler, that it is really a constant?
It isn't a constant though. It can still be modified by the constructor. Only a compile time constant is allowed for the size of an array. When the compiler says "constant expression", it is not meaning an expression which returns a constant value, but an constant, such as "52" or "45" or something along those lines.
Use std::vector instead.
EDIT: In response to "I know array sizes already, and there will be a few child-classes with different constants"
The only way to do that is to use a template.
template<size_t x>
class A {
public:
void f() {
double y[x];
}
};
typedef A<2> B;
The behaviour you expect could be achieved using the following template.
Note that this is actually unreliable, disgusting and could be used only as "a sample". Use std::vector instead.
template <size_t a = 0>
class A {
public:
A() { }
void f() {
int y[a];
y[0] = 5;
}
};
class B : A<2> {
B() { }
};
void main() {
A<1> a;
a.f();
// Undefined behaviour - creating an array of size 0
// At least, MSVS2008 treats it as an error :)
// A<0> a_;
}
There's "constant", and then there's "constant". If you want to allocate an array on the stack like that, the compiler needs the length of the array at compile time, and based on what you've given there it can't figure that out. Interestingly, gcc supports an extension (not supported in standard C++) that allows for stack allocation for variable lengths.
I don't know if it will work for your purposes, but one possibility would be to make it a template parameter:
template <int size>
class A {
double y[size];
};
In this case, you'd probably want to create an instance of A in B instead of using inheritance.
The other obvious possibility would be to use a tr1::array object instead. This is is also a template, so the idea is pretty much the same, but it's already written, tested and working so you can avoid all that. If your compiler doesn't supply TR1 classes, Boost has a mostly conforming implementation (boost::array).