开发者

Best way to implement globally scoped data

I'd like to make program-wide data in a C++ program, without running into pesky LNK2005 errors when all the source files #includes this "global variable repository" file.

I have 2 ways to do it in C++, and I'm asking which way is better.

The easiest way to do it in C# is just public static members.

C#:

public static class DataContainer
{
    public static Object data1 ;
    public static Object data2 ;
}

In C++ you can do the same thing

C++ global data way#1:

class DataContainer
{
public:
  开发者_如何转开发  static Object data1 ;
    static Object data2 ;
} ;
Object DataContainer::data1 ;
Object DataContainer::data2 ;

However there's also extern

C++ global data way #2:

class DataContainer
{
public:
    Object data1 ;
    Object data2 ;
} ;
extern DataContainer * dataContainer ; // instantiate in .cpp file

In C++ which is better, or possibly another way which I haven't thought about?

The solution has to not cause LNK2005 "object already defined" errors.


If you absolutely have to have some global objects then the simplest way is to just to declare them extern in a header file included anywhere that needs access to them and define them in a single source file.

Your way #1 uses a class with only static members which means that it is essentially doing the job of a namespace so why not just use a namespace?

Way #2 aggregates both objects in a single class but if there is no true interdependency between the two objects there is no particular benefit to this.

I'd recommend putting the objects in a namespace prevent pollution of the global namespace with potentially common identifiers like data1,

// File: globaldata.h
#ifndef GLOBALDATA_H
#define GLOBALDATA_H

#include "Object.h" // Definition of Object might be here

namespace GlobalData
{
    extern Object data1;
    extern Obejct data2;
}

#endif GLOBALDATA_H

.

// File: globaldata.cc
#include globaldata.h

namespace GlobalData
{

    Object data1;
    Object data2;
}

Then you can access them in other places like this.

#include "globaldata.h"

// Does something with global data
void f()
{
    GlobalData::data1.doSomething();
}


A better way would be to put your objects in a namespace.

// header
namespace global // or any appropriate name
{
   extern Object data1 ;
   extern Object data2 ;
}

// cpp
namespace global // or any appropriate name
{
   Object data1 ;
   Object data2 ;
}

As precised in commments: to do this, don't forget to use extern qualifier to the declarations (in the header file) to specify that there is only one instance (in the cpp file) of each object.


Public static variables are just globals, and globals are bad. If an object depends on some data you want to make global, make a setter for this dependency and have some kind of “factory” class that will put your application together from small, independent parts, providing the global dependencies through the setters. Like this, in pseudocode:

class A:
    has dependency1 of type X;
    has dependency2 of type Y;

class Factory:
    has sharedX of type X;
    has sharedY of type Y;

    init:
        sharedX = createX;
        sharedY = createY;

    wireApplication:
        instanceOfA = createA;
        instanceOfA.setDependency1(sharedX);
        instanceOfA.setDependency2(sharedY);
        return instanceOfA;

This way the A’s dependencies are not hard-coded by accessing static variables. That has several advantages. First, they are more visible, as you don’t secretly pull information from other classes in the implementation file. Second, they are not set in stone, because you can actually create A without pulling X and Y with it. Third, you have precise control over the lifetime of X and Y.

See the excellent series of blog posts by Miško Hevery about singletons – you can start with Singletons are Pathological Liars and follow the links from there.


You are confused. Your problem ("LNK2005") is with linkage, not the source language level scoping. C# conflates these things (although I don't think that's necessarily a bad thing) much more so than C++ (but C++ does so as well, to some extent, e.g. the extern keyword). No solution to this problem will live entirely in the realm of the compiler and the preprocessor. The linker and how you build your program will come into play.

Both of your solutions are actually using extern (external linkage) to solve the problem, it is just implicit in the first case. Really, "program wide" data is pretty vague. Do you mean "process wide"? Or shared across all instances of a program? Based on the error message, I assume you're dealing with windows. Does your program have/use DLLs? Does this "program wide" data need to be, or should be shared across different dlls?


In a header file (I'll call it Data.h):

namespace Data
{
    extern Object data1;
    extern Object data2;
}

In any source files that need to know about it:

#include "Data.h"

For Data.cpp, you can write either

#include "Data.h"

Object Data::data1;
Object Data::data1;

or

#include "Data.h"

namespace Data
{
    Object data1;
    Object data2;
}


KISS.

DataContainer.h

#pragma once
namespace DataContainer {
    extern Object data1;
    extern Object data2;
} // namespace DataContainer

DataContainer.cpp

#include <DataContainer.h>
namespace DataContainer {
    Object data1;
    Object data2;
}// namespace DataContainer
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜