This problem only occurs with g++ 4.8.2 for ARMv6 (stock pidora); it compiles without error or warning on x86_64 w/ clang 3.4.2 and g++ 4.8.3. I am having a hard time not seeing it as a compiler bug, but wanted to get some other opinions.
It involves a simple member variable that g++ keeps insisting is an array and
error: array must be initialized with a brace-enclosed initializer
The header for the class looks like this:
namespace SystemStateMonitor {
class ramInput : public input, public inputFile {
public:
typedef enum {
RATIO,
PERCENT,
KiBYTES,
MiBYTES
} style_t;
ramInput (
const std::string &label = "RAM",
style_t style = style_t::PERCENT
);
unsigned int getAvailable ();
double getDV ();
double ratio ();
protected:
style_t style;
unsigned int available;
void setStyle (style_t);
friend input* jsonInputRAM (jsonObject);
};
}
The constructor looks like this:
#define PROC_FILE "/proc/meminfo"
using namespace std;
using namespace SystemStateMonitor;
ramInput::ramInput (
const string &label,
ramInput::style_t s
) :
input (label),
inputFile (PROC_FILE),
style (s),
available (0)
{
setStyle(style);
}
And when I compile this with the ARMv6 g++, I get:
inputs/ramInput.cpp:19:14: error: array must be initialized with a brace-enclosed initializer
available (0)
^
The superclasses do not have any member "available"; there is no potential weird collision. Interestingly, if I then modify the constructor:
) :
input (label),
inputFile (PROC_FILE),
style (s)
{
available = 0;
setStyle(style);
}
I now get the same error for style (s). If I then do the same thing with style (move initialization into the body), I get the error for inputFile (PROC_FILE), which is even more bizarre because that's a super constructor call.
inputs/ramInput.cpp:17:22: error: array must be initialized with a brace-enclosed initializer
inputFile (PROC_FILE)
^
Unfortunately but not surprisingly, an SSCCE starting with this:
class test {
public:
test () : x(0) { };
unsigned int x;
};
Does not reproduce the problem.
What could be going wrong here? Am I right to believe this isn't my fault?
As Mike Seymour points out in comments on the question, the cascading nature of the error indicated the compiler was simply pointing to the end of the problem initialization list, rather than the correct entry. The array turned out to be in a superclass constructor default initializer:
std::array<double,2> range = { 0 }
That particular g++ chokes on that, and:
std::array<double,2> range = { 0.0, 0.0 }
But:
std::array<double,2> range = { }
Works. Good thing I didn't want any non-zero values there...
Related
In our project we often use a construct like this (simplified for clarity, we actually use a more safe to use version):
struct Info
{
Info(int x, int y) : m_x(x), m_y(y)
{}
int m_x;
int m_y;
};
struct Data
{
static const Info M_INFO_COLLECTION[3];
};
const Info Data::M_INFO_COLLECTION[] = // global-constructors warning
{
Info(1, 2),
Info(10, 9),
Info(0, 1)
};
M_INFO_COLLECTION can contain a large number of data points. The initialization part resides in the cpp file, which is often code-generated.
Now this structure gives us a fair amount of global-constructors-warnings in clang across our code base. I've read in a blog post that using warnings in the -Weverything group is a bad idea for nightly builds and I agree, and even the clang docdoes not recommend to use it.
Since the decision to switch off the warning is out of my hands, I could use a helpful trick to get rid of the warning (and a potential static initialization order fiasco), by converting the static member into a function initializing and returning a local static variable.
However, since our project does not use dynamically allocated memory as a rule, the original idea has to be used without a pointer, which can lead to deinitialization problems when my Data class is used by other objects in a weird way.
So, long story short: The global-constructors warning points to a piece of code that I can review as safe, since I know what the Data class does. I could get rid of it using a workaround that can lead to problems if other classes use Data in a particular way, but this won't generate a warning. My conclusion is that I would be better off just leaving the code as it is and ignore the warning.
So now I am stuck with a bunch of warnings, that may in some cases point to a SIOF and which I would like to address, but which get buried unter a mountain of warnings that I deliberately do not want to fix, because the fix would actually make things worse.
This brings me to my actual question: Is clang too strict in its interpretation of the warning? From my limited compiler understanding, shouldn't it be possible for the compiler to realize that in this particular case, the static member M_INFO_COLLECTION cannot possibly lead to a SIOF, since all its dependencies are non-static?
I played around with this issue a bit and even this piece of code gets the warning:
//at global scope
int get1()
{
return 1;
}
int i = get1(); // global-constructors warning
Whereas this works fine, as I would expect:
constexpr int get1()
{
return 1;
}
int i = 1; // no warning
int j = get1(); // no warning
This looks fairly trivial to me. Am I missing something or should clang be able to suppress the warning for this example (and possibly my original example above as well)?
The problem is that it is not constant initialized. This means that M_INFO_COLLECTION may be zero-initialized and then dynamically initialized at run time.
Your code generates assembley to set M_INFO_COLLECTION dynamically because of the "global constructor" (non-constant initialization): https://godbolt.org/z/45x6q6
An example where this leads to unexpected behaviour:
// data.h
struct Info
{
Info(int x, int y) : m_x(x), m_y(y)
{}
int m_x;
int m_y;
};
struct Data
{
static const Info M_INFO_COLLECTION[3];
};
// data.cpp
#include "data.h"
const Info Data::M_INFO_COLLECTION[] =
{
Info(1, 2),
Info(10, 9),
Info(0, 1)
};
// main.cpp
#include "data.h"
const int first = Data::M_INFO_COLLECTION[0].m_x;
int main() {
return first;
}
Now if you compile main.cpp before data.cpp, first may access Info out of it's lifetime. In practice, this UB just makes first 0.
E.g.,
$ clang++ -I. main.cpp data.cpp -o test
$ ./test ; echo $?
0
$ clang++ -I. data.cpp main.cpp -o test
$ ./test ; echo $?
1
Of course, this is undefined behaviour. At -O1, this issue disappears, and clang behaves as if M_INFO_COLLECTION is constant initialized (as-if it reordered the dynamic initialization to before first's dynamic initialization (and every other dynamic initialization), which it is allowed to do).
The fix to this is to not use global constructors. If your static storage duration variable is able to be constant initialized, make the relevant functions/constructors constexpr.
If you are not able to add constexprs or have to use a non-constant initialized variable, then you can resolve the static initialization order fiasco without dynamic memory using placement-new:
// data.h
struct Info
{
Info(int x, int y) : m_x(x), m_y(y)
{}
int m_x;
int m_y;
};
struct Data
{
static auto M_INFO_COLLECTION() -> const Info(&)[3];
static const Info& M_ZERO();
};
// data.cpp
#include "data.h"
#include <new>
auto Data::M_INFO_COLLECTION() -> const Info(&)[3] {
// Need proxy type for array reference
struct holder {
const Info value[3];
};
alignas(holder) static char storage[sizeof(holder)];
static auto& data = (new (storage) holder{{
Info(1, 2),
Info(10, 9),
Info(0, 1)
}})->value;
return data;
}
const Info& Data::M_ZERO() {
// Much easier for non-array types
alignas(Info) static char storage[sizeof(Info)];
static const Info& result = *new (storage) Info(0, 0);
return result;
}
Though this does have minor runtime overhead for each access, especially the very first, compared to regular static storage duration variables. It should be faster than the new T(...) trick, since it doesn't call a memory allocation operator.
In short, it's probably best to add constexpr to be able to constant initialize your static storage duration variables.
I want to initialize an array of pointers the nice way.. Something like
handler[numberOfIndexes] = {&bla, &ble, &bli, &blo , &blu};
But it doens't work this way. I get an error, obviously, because I'm trying to place an array of pointers to functions, in a single pointer to function:
cannot convert ‘<brace-enclosed initializer list>’ to ‘void (A::*)()’ in assignment
So, here's the code for you to test:
#include <iostream>
#include <list>
using namespace std;
class A
{
private:
void first();
void second();
void third ();
// and so on
void(A::*handlers[4])(void);
public:
A();
};
void A::first()
{
}
void A::second()
{
}
void A::third()
{
}
A::A()
{
//this is ugly
handlers[0] = &A::first;
handlers[1] = &A::second;
handlers[2] = &A::third;
//this would be nice
handlers[4] = {&A::first,&A::second,&A::third,0};//in static this would work, because it would be like redeclaration, with the type speficier behind
}
int main()
{
A sup;
return 0;
}
UPDATE:
In Qt this doesn't work.
I get :
syntax error: missing ';' before '}'
And if I change to
A::A() : handlers ({&A::first, &A::second, &A::third, 0})//notice the parentheses
then a this happens
Syntax Error: missing ')' before '{'
Warning: The elements of the array "A :: Handlers" are by default "initialized.
So, what's the problem with Qt?
By this point, you should have understood what I want to do. Just do a nice initialization of the array of pointers.
Thank you.
Just use an actual initialization, not an assignment (arrays cannot be assigned to).
A::A() : handlers {&A::first, &A::second, &A::third, 0} {}
Error received:
error: no matching function for call to ‘stout::SCGI::SCGI()’
Code:
#include <gtest/gtest.h>
#include <vector>
#include "../../../../stout/cgi/scgi/scgi.hpp"
class SCGITest : public ::testing::Test
{
protected:
int string_length;
std::vector<char> netstring;
stout::SCGI scgi;
public:
SCGITest()
{
const char *c_netstring =
"70:CONTENT_LENGTH\00027\0"
"SCGI\0001\0"
"REQUEST_METHOD\0POST\0"
"REQUEST_URI\0/deepthought\0"
","
"What is the answer to life?";
string_length = 102;
for(int i = 0; i < string_length; ++i)
{
netstring.push_back(c_netstring[i]);
}
// SHOULD CALL stout::SCGI::SCGI(const std::vector<char>&)
this->scgi = stout::SCGI scgi {netstring};
scgi.init();
}
};
TEST_F(SCGITest, NetstringSize)
{
EXPECT_EQ(netstring.size(), string_length);
}
TEST_F(SCGITest, SCGILength)
{
EXPECT_EQ(scgi.get_length(), 70);
}
TEST_F(SCGITest, SCGIContentLength)
{
EXPECT_EQ(scgi.get_header("CONTENT_LENGTH"), "27");
}
TEST_F(SCGITest, SCGIVersion)
{
EXPECT_EQ(scgi.get_header("SCGI"), "1");
}
TEST_F(SCGITest, SCGIRequestMethod)
{
EXPECT_EQ(scgi.get_header("REQUEST_METHOD"), "POST");
}
TEST_F(SCGITest, SCGIRequestURI)
{
EXPECT_EQ(scgi.get_header("REQUEST_URI"), "/deepthought");
}
TEST_F(SCGITest, SCGIRequestBody)
{
EXPECT_EQ(scgi.get_request_body(), "What is the answer to life?");
}
Question:
When I try and construct and object of type stout::SCGI::SCGI using the constructor stout::SCGI::SCGI(const std::vector<char>&) it fails in the above code with the error message shown at the top of this post.
It seems that before the constructor has finished it has already tried to call the default (empty) constructor for the scgi private member variable. I do not want an empty constructor on my class and have had to temporarily add one to fix this issue while I investigate it.
I've read other questions regarding this issue but can't seem to find a solution for this particular case.
If it matters I'm compiling the above code using G++ 4.9.2 on Arch Linux with the -std=c++14 flag.
Your stout::SCGI type has no default constructor, yet you are not initialising this->scgi. Sure, you're assigning to it at the end of your constructor body, but that's not at all the same thing.
You need to initialise any members that are const or which cannot be default-constructed:
struct Foo
{
stout::SCGI scgi;
Foo()
: scgi(/* ctor arguments here */) // this is a "member initialisation list"
{};
};
Also, the following is simply not valid syntax:
this->scgi = stout::SCGI scgi {netstring};
That lone scgi is clearly superfluous. At best, you want:
this->scgi = stout::SCGI{netstring};
However, once you're initialising this->scgi instead of waiting to assign to it, then this goes away completely.
What is scgi supposed to be here? I think you just want
this->scgi = stout::SCGI {netstring};
I am trying to write classes and structs in C++, for example:
using namespace std;
struct Position {
int x;
int y;
};
class Maze {
Position pos;
pos.x = 0;
pos.y = 0;
};
int main() {
return 0;
}
but it rises some errors when I try to compile it:
(gcc version 4.3.2)
10: error: ISO C++ forbids declaration of 'pos' with no type
10: error: expected ';' before '.' token
11: error: ISO C++ forbids declaration of 'pos' with no type
11: error: expected ';' before '.' token
It looks like this piece of code is pretty much the same as it in C++ Tutorial: Struct.
Answers to some other posts about "error: ISO C++ forbids declaration of '...' with no type" (such as this) suggest to add namespace, but I find it hard see what is the reason why it does not work here.
In summary, I have the following questions:
What does this error actually mean in this case?
What does this error mean in general?
Why this code does not work?
How to make it work?
I will be grateful if someone could give an answer, and/or a direction of research/reading.
This code
pos.x = 0;
pos.y = 0;
needs to go in a function. One way would be to put it in the constructor, something like:
class Maze {
Position pos;
public:
Maze() {
pos.x = 0;
pos.y = 0;
}
};
Note that I made the constructor public as otherwise you wouldn't be able to use the Maze class
Edit: Actually answering your questions:
What does this error actually mean in this case?
The compiler doesn't know what to do with pos.x = 0 as it is expecting declarations at this point, not code.
What does this error mean in general?
It usually means that the compiler doesn't know how to process the declaration you wrote.
Why this code does not work?
Because you put executable code where declarations are supposed to go.
How to make it work?
See the code above.
Since this question is titled "ISO C++ forbids declaration of “something” with no type", here's a more generic answer. C++ is unable to find the type, so just specify the type.
In my case, I was able to solve it only after adding a forward declaration.
A.hpp
class A
{
};
B.hpp
#include "A.hpp"
class B
{
public:
A* inst;
};
This caused the error of ISO C++ forbids declaration of A with no type.
So I made a change in B.hpp as such:
#include "A.hpp"
class A;//the forward declaration
class B
{
public:
A* inst;
};
and it compiled fine!
For a start, you cannot initialise the members at the top level of the class:
class Maze {
Position pos;
pos.x = 0;
pos.y = 0;
};
You have to provide a constructor of some sort and, if you're after a default state for the position, that's probably where you want the initialisation done. Objects should generally be responsible for their own initialisation and tear-down:
using namespace std;
struct Position {
int x;
int y;
Position() : x(0), y(0) {}
};
class Maze {
Position pos;
};
int main () {
return 0;
}
Lines 10 and 11 are
pos.x = 0;
pos.y = 0;
The compiler is assuming that you wanted to declare variables named 'pos.x' and 'pos.y', and is complaining because you haven't told it what type those variables are.
What want to do is to move those two assignments inside a constructor, just as The Dark suggests.
However, if I wasn't sure how complex things might get later on, I might write it this way:
class Position {
private:
int x;
int y;
public:
Position(int x0, int y0) : x(x0), y(y0) {
// Any other initialization here.
}
inline int getX() { return x; }
inline int getY() { return y; }
inline void setX(int x0) { x = x0; }
inline void setY(int y0) { y = y0; }
}
class Maze : public Position {
Maze() : Position(0,0) {
// Any other initialization here.
}
}
Some may say that this is overkill. It may well be, I don't know how complex your final problem really is. If you don't know for sure either, going with a class is probably safest.
The whole point to classes is data encapsulation. Don't expose anything you don't have to, and that way you don't have to worry about some other code changing values in ways you didn't expect. Using a struct may be sufficient, but if it isn't, going back and converting from a struct to a class may be more difficult than just going ahead with a class now.
I have a classcalled Tracer in C++. In my Tracer.h file I have:
class Tracer{
public:
// not useful to the question.
private:
Logger *m_logger;
const char *m_who;
const char *m_fileName;
const void * m_theObject;
int m_lineNum;
int m_log_level;
}
And in Tracer.cpp I have:
Tracer::Tracer(
Logger *logger,
const void *theObject,
const char *who,
const char *file,
int line,
int log_level
) :
m_logger(logger),
m_who(who),
m_fileName(file),
m_lineNum(line),
m_theObject(theObject),
m_log_level(log_level)
{
// more implementation which is not useful to the problem.
The problem is, when I initialize m_theObject(theObject), I get the following warning:
/home/pribeiro/workspace/Tracer.h:80: warning: 'const void* Tracer::m_theObject'
/home/pribeiro/workspace/Tracer.cpp:27: warning: when initialized here
Tracer.h:80 is the declaration of m_theObject in the Tracer.h and Tracer.cpp:27 is the m_theObject(theObject line.
In my compilation level, warnings are treated like errors. Why is the compiler complaining about the initiliazation of a const void * pointer?
That's not the whole warning. It's actually warning that m_lineNum and m_theObject are being initialised in the wrong order (see Member fields, order of construction):
Tracer.h:80: warning: 'const void* Tracer::m_theObject' is initialized before 'int Tracer::m_lineNum'
Tracer.cpp:27: warning: when initialized here
The fix is to swap the order of initialisation, or the order of definition:
Tracer::Tracer(
Logger *logger,
const void *theObject,
const char *who,
const char *file,
int line,
int log_level
) :
m_logger(logger),
m_who(who),
m_fileName(file),
m_theObject(theObject), // here
m_lineNum(line), // and here
m_log_level(log_level)
{
// more implementation which is not useful to the problem.
Sometimes compilers give a warning when members are initialised in the member initialisation list in a different order than they are declared in the header. I have seen g++ do this before. If you reorder your initialisation list so that it is in the same order as the members appear in your header file you should see this warning disappear.
The issue here is that, as per the C++ Standard, member variables are always (ALWAYS) initialized in the order of declaration, regardless of the order you give in the constructor.
The compiler nicely warns you about your misfit, because possibly you introduce unintended dependency chains.
Example:
struct Foo {
int _1, _2, _3;
Foo() : _3(_2+_1), // Third initialization
_2(_1+_1), // Second initialization
_1(1) // First initialization
{}
};
#include <iostream>
int main () {
Foo f;
std::cout << f._1 << f._2 << f._3 << '\n';
}
Output:
123
But the order of member initializers may let the maintainer think he could do better:
struct Foo {
int _1, _2, _3;
Foo() : _3(3),
_2(_3-1),
_1(_2-1)
{}
};
#include <iostream>
int main () {
Foo f;
std::cout << f._1 << f._2 << f._3 << '\n';
}
One might again expect the output of 123 as it looks like _3 is initiliazed first in that constructor. But that's not true:
./teh_program
13451434436167553
./teh_program
134514344118742913
./teh_program
13451434495068033
The results are totally unpredictable, multiple runs give different results without even recompiling. And the compiler is to prevent accidents like this.