consider the following namespace:
// foo.h
namespace foo
{
extern int bar;
}
//foo.cpp
namespace foo
{
extern int bar = 42;
}
is there a way to change the value of bar somewhere else in the project (i.e, not inside the namespace)?
I mean something like:
// in some other .cpp file
#include foo.h
int setBar(int x)
{
foo::bar = x;
}
is there a way to change the value of bar somewhere else in the project (i.e, not inside the namespace)?
Yes, almost exactly as you've shown.
The only issue in your sample code is that you used extern in your foo.cpp file where you define your foo::bar variable. You need to remove extern from foo.cpp:
#include <iostream>
// foo.h
namespace foo
{
extern int bar; // use extern in header file to declare a variable
}
// foo.cpp
namespace foo
{
int bar = 42; // no extern in cpp file.
}
int setBar(int x)
{
std::cout << "old foo::bar: " << foo::bar << std::endl;
foo::bar = x;
std::cout << "new foo::bar: " << foo::bar << std::endl;
}
int main()
{
setBar(999);
}
Output:
old foo::bar: 42
new foo::bar: 999
If you declare a variable as extern, then you tell the compiler that he shall not define the variable in the current translation unit but rather let the linker look for a variable defined in another translation unit. Hence extern just declares a variable, but does not define it. Consequently, initialising a variable that has not beed defined makes no sense.
So you should actually write:
// foo.h
namespace foo
{
extern int bar; // Just declare...
}
//foo.cpp
namespace foo
{
int bar = 42; // Define and initialise
}
Note that you still provide a header file with extern int bar, which - when included by other translation units than foo.cpp - declare variable bar such that the code may refer to it even if it is defined in another library (e.g. in foo.o).
Related
use.cpp
#include "my.h"
int main()
{
int foo = 7;
print_foo();
print(99);
}
my.h
#pragma once
extern int foo;
void print_foo();
void print(int i);
my.cpp
#include<iostream>
#include "my.h"
void print_foo()
{
std::cout << foo;
}
void print(int i)
{
std::cout << i;
}
So my question is pretty simple I declare an extern int foo in the header file then I DEFINE foo in main, why does this not work? If I don't define foo in main and define it outside of main in use.cpp then it works but when I define it in main() it doesn't. Why?
At global scope, the declaration
extern int foo;
declares a variable named foo that has external linkage, meaning that it might be defined in another translation unit.
At block scope (i.e., as a statement in the body of a function), the definition
int foo = 7;
has no linkage. That means that the compiler will never consider this foo to be the same entity as another foo from another scope. Therefore, this simply creates another variable that's unrelated to the global one, and does not initialize the global one.
I know what "forward function declaration" means, but I want get the same with variables.
I have this code snippet:
#include <iostream>
int x;
int main()
{
std::cout << x << std::endl; // I want get printed "2" but I get compile error
return 0;
}
**x = 2;**
In the std::cout I want print "2" value, but trying to compile this I get this compile error: error: 'x' does not name a type.
While this doesn't appear somthing of programmatically impossible, I can't compile successfully.
So what is the right form to write this and obtain a forward variable declaration?
Variable declarations need extern. Variable definitions need the type, like declarations. Example:
#include <iostream>
extern int x;
int main()
{
std::cout << x << '\n';
}
int x = 2;
Normally you'd use extern to access a variable from a different translation unit (i.e. from a different .cpp file), so this is mostly an artifical example.
You can declare
extern int x;
in this file, and in some other file
int x = 2;
You could use Class and declare variable inside. Also, anonymous namespace is needed as Vlad said. Example:
#include<iostream>
namespace
{
class MyClass
{
public:
static int x;
};
}
int main()
{
std::cout << MyClass::x;
}
int MyClass::x = 2;
This question builds off these two stackoverflow posts:
multiple definition in header file
Multiple definition of namespace function
Here's the question: Why doesn't the multiple definition error appear for classes/structs/enums? Why does it only apply to functions or variables?
I wrote some example code in an effort to capture my confusion. There are 4 files: namespace.h, test.h, test.cpp, and main.cpp. The first file is included in both test.cpp and main.cpp, which leads to the multiple definition error if the correct lines are uncommented.
// namespace.h
#ifndef NAMESPACE_H
#define NAMESPACE_H
namespace NamespaceTest {
// 1. Function in namespace: must be declaration, not defintion
int test(); // GOOD
// int test() { // BAD
// return 5;
//}
// 2. Classes can live in header file with full implementation
// But if the function is defined outside of the struct, it causes compiler error
struct TestStruct {
int x;
int test() { return 10; } // GOOD
};
//int TestStruct::test() { // BAD
// return 10;
//}
// 3. Variables are also not spared from the multiple definition error.
//int x = 20; // BAD
// 4. But enums are perfectly safe.
enum TestEnum { ONE, TWO }; // GOOD
}
#endif
// test.h
#ifndef TEST_H
#define TEST_H
class Test {
public:
int test();
};
#endif
// test.cpp
#include "test.h"
#include "namespace.h"
int NamespaceTest::test() {
return 5;
}
int Test::test() {
return NamespaceTest::test() + 1;
}
// main.cpp
#include <iostream>
#include "namespace.h"
#include "test.h"
int main() {
std::cout << "NamespaceTest::test: " << NamespaceTest::test() << std::endl;
Test test;
std::cout << "Test::test: " <<test.test() << std::endl;
NamespaceTest::TestStruct test2;
std::cout << "NamespaceTest::TestStruct::test: " << test2.test() << std::endl;
std::cout << "NamespaceTest::x: " << NamespaceTest::TestEnum::ONE << std::endl;
}
g++ test.cpp main.cpp -o main.out && ./main.out
NamespaceTest::test: 5
Test::test: 6
NamespaceTest::TestStruct::test: 10
NamespaceTest::x: 0
After reading cppreference: inline specifier, I have a partial answer. The rules for inline stipulate that functions defined within classes are considered inline. And inline functions are permitted to have duplicate definitions provided (1) they live in separate translation units and (2) are identical. I'm paraphrasing, but that's the gist.
That explains why the functions are legal, but not why multiple definitions of the class or enum are ok. Likely a similar explanation I imagine, but it would be good to know for sure.
Generally when you compile a definition that is namespace scoped (like functions or global variables), your compiler will emit a global symbol for it. If this appears in multiple translation units, there will be a conflict during link-time since there are multiple definitions (which happen to be equivalent, but the linker can't check this).
This is part of the one definition rule: Exactly one definition of a function or variable is allowed in the entire program, in one of the translation units.
There are some exceptions to this, for example, class definitions and inline functions/variables. However, definitions must be the exact same (textually) in all the translation units they appear in. Class definitions are meant to be #included, so it makes sense to allow them to appear in multiple translation units.
If you define a member function inside the class body they are implicitly inline because otherwise you would not be able to include the class definition with the member function definition without breaking ODR. For example, these three are functionally equivalent:
struct TestStruct {
int x;
int test() { return 10; }
};
// Could have been written
struct TestStruct {
int x;
inline int test() { return 10; }
};
// Or as
struct TestStruct {
int x;
int test(); // The `inline` specifier could also be here
};
inline int TestStruct::test() { return 10; }
You can do this to your namespace scoped functions/variables too: inline int test() { return 5; } and inline int x = 20; would have compiled with no further issue.
This is implemented by the compiler emitting "specially marked" symbols for inline entities, and the linker picking one arbitrarily since they should all be the same.
The same exception to ODR also exists for templated functions / variables and enum declarations, since they are also meant to live in header files.
Is it legal to define the implementation of a function or class members outside the unnamed (anonymous) namespace they've been defined inside.
My compiler accepts it but I want to be sure it's legal
e.g.
////////////////
// foo.cpp
namespace {
struct X
{
void foo(int x);
};
}
// Is this legal?
void X::foo(int x)
{
}
The reason is I would like to avoid the unnecessary indentation imposed by our uncrustify formatting
It is really no different than the following, which is totally legit:
namespace ns {
struct s {
void f();
};
}
using namespace ns;
void s::f() { }
The names from the named namespace are brought into the global namespace and thus definitions can be provided for them there. The only difference with the unnamed namespace is that it has no name (really, it has some unique, unutterable name) and the using namespace is implicit.
#include <iostream>
using namespace std;
namespace
{
struct X
{
X(int);
int x_;
};
}
X::X(int x) : x_(x) {}
int main()
{
X x(5);
cout << x.x_ << "\n";
return 0;
}
Compiles (and runs) under gcc 4.6.0
Yes. It's perfectly legal. The difference an unnamed namespace makes is that, the content of the namespace is available only within the file it's declared. If it's in .h file then, it will be added to all the subsequent .cpp file and every .cpp file will have a unique copy of the contents of the namespace.
In fact it's a better way to declare a global static variable. Now see, what kind of difference it will make:
namespace {
struct X
{
void foo(int x);
};
int i; // declare this global variable
}
If you put this code inside a header file then, wherever that header file is #includeed, all those .cpp file will have a different copy of int i; inside them. Changing the value of i in one .cpp file doesn't affect the other .cpp file.
Moreover, it will not give linker error for multiple definitions, since it's in unnamed namespace.
Edit: To evaluate it more, define the namespace as following:
// x.h
namespace
{
struct X
{
void foo(int x)
{
static int c; // static inside the function
cout<<"a = "<<(c++)<<endl;
}
};
}
Now #include this header file in 2 different .cpp files. In both of them try to call foo() with object of X. It will print:
a = 0
a = 0
Which means that X::foo() in both the .cpp files are different. If you give the namespace a name and repeat the same thing, it will output
a = 0
a = 1
Thus unnamed namespace creates a different copy for each translation unit.
It's legal in your scenario, but in one scenario, it will cause compiler ambiguous error.
In case have another class in X.h:
// X.h
struct X
{
void foo(int x) { }
};
And in foo.cpp, need to use the X defined in X.h
////////////////
// foo.cpp
#include "X.h"
namespace {
struct X
{
void foo(int x);
};
// use the X declared in anonymous namespace
void test()
{
X x;
x.foo(3);
}
}
// reference to 'X' is ambiguous
void X::foo(int x)
{
}
void otherFunction()
{
// Use struct X in X.h
::X x;
x.foo(3);
}
if leave the implementation code out of the anonymous namespace, compiler complains ambiguous. If move the implementation code inside anonymous namespace, it works fine.
I have a variable that I would like to use in all my classes without needing to pass it to the class constructor every time I would like to use it. How would I accomplish this in C++?
Thanks.
global.h
extern int myVar;
global.cpp
#include "global.h"
int myVar = 0; // initialize
class1.cpp
#include "global.h"
...
class2.cpp
#include "global.h"
...
class3.cpp
#include "global.h"
...
MyVar will be known and usable in every module as a global variable. You do not have to have global.cpp. You could initialize myVar in any of the class .cpp's but I think this is cleaner for larger programs.
While I would like to avoid global variables like the plague as our software cannot be multithreaded effectively due to the high reliance on global variables, I do have some suggestions:
Use a Singleton. It will allow you to keep the code and access clean. Part of the problem with a global variable is you don't know what code has modified it. You could set the value of global somewhere in your function relying on the hope that no one else will change it, but function your code calls, fooA, changes it and now your code is a) broken, and b) hard to debug.
If you have to use a global variable without touching the singleton pattern, look at fupsduck's response.
If you're not going to use the Singleton pattern as Lyndsey suggests, then at least use a global function (inside a namespace) to access the variable. This will give you more flexibily in how you manage that global entity.
// mymodule.h
namespace mynamespace // prevents polluting the global namespace
{
extern int getGlobalVariable();
}
// mymodule.cpp
namespace mynamespace
{
int myGlobalVariable = 42;
int getGlobalVariable()
{
return myGlobalVariable;
}
}
Just declare it outside the class:
Header file:
extern int x;
class A {
int z;
public:
A() : z(x++) {}
};
One source file:
int x = 0;
keyword extern
//file1.cpp
int x = 0;
//file1 continues and ends.
//file2.cpp
extern int x; //this gets tied into file1.cpp's x at link time.
//file2.cpp goes on and ends
Declare the variable as extern in a common header.
Define it in any source file.
// L.hpp
struct L { static int a; };
// L.cpp
int L::a(0);
The below solution should be simple enough as per the title "How to declare a global variable that could be used in the entire program
" .
If you want to use it in a different file then make use of extern keyword.
Please let me know if there is any issue with the solution
#include<iostream>
using namespace std;
int global = 5;
class base {
public:
int a;
float b;
base (int x) {
a = global;
cout << "base class value =" << a << endl;
}
};
class derived : public base {
public:
int c;
float d;
derived (float x, int y) : base (y)
{
d = global;
cout << "derived class value =" << d << endl;
}
};
int main ()
{
derived d(0,0);
cout << "main finished" << endl;
return 0;
}
if you want to declare it in different header files/cpp files, just declare it extern outside of other files
//file1.c
int x=1;
int f(){}
//file2.c
extern int x;