Thread: File-scope objects

  1. #1
    Registered User
    Join Date
    Oct 2009
    Posts
    48

    File-scope objects

    Hey,
    I am trying to declare some objects as static file-scope objects but I do not want to initialize them outside of a function.

    I've tried these ways
    Code:
    static Foo f;
    ...
    void bar()
    {
         f(0,1,2);
         ...
    }
    Code:
    namespace
    {
        Foo f;
    }
    void bar()
    {
        f(0,1,2);
    }
    Code:
    void bar()
    {
        Foo f(0,1,2);
    }
    void bar2()
    {
         extern Foo f;
    }
    But alas, I am here looking for help. What I need is to have multiple functions inside the same file access a static copy of f, but I do not know the arguments at compile time.

    Thanks

  2. #2
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    You can use new and get that to call the constructor with the appropriate arguments. It's not a great solution, but it might fit your desires.

    Can't you just assign the value of f rather than constructing it? Perhaps I misunderstood.

  3. #3
    Registered User
    Join Date
    Oct 2009
    Posts
    48
    Quote Originally Posted by twomers View Post
    You can use new and get that to call the constructor with the appropriate arguments. It's not a great solution, but it might fit your desires.
    That would work. I don't know what I was thinking. If I do not know the arguments that will be passed to f at compile time then I will need to use dynamic allocation, thus the new operator, correct?

  4. #4
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    You don't need to have dynamic allocation
    Code:
    #include <cstdlib>
    #include <iostream>
    
    class foo
    {
    public:
      foo(int a) {}
    };
    
    int main()
    {
       int x;
       std::cin >> x;
       foo f(x);
    }
    At compile time no memory is allocated.
    The difference is that new allocates memory on the heap, it has to search for a free block of memory. This is done at run-time. The above code though allocate memory from the stack. When main is called it knows how much extra memory it needs for the objects created inside it.

  5. #5
    Registered User
    Join Date
    Oct 2009
    Posts
    48
    Quote Originally Posted by C_ntua View Post
    At compile time no memory is allocated.
    The difference is that new allocates memory on the heap, it has to search for a free block of memory. This is done at run-time. The above code though allocate memory from the stack. When main is called it knows how much extra memory it needs for the objects created inside it.
    Well that brings me to my original problem then. What I need is to be able to initialize an object in a function ( called void initialize()) and be able to use that object in another function. Taking the third example I gave, the object f must be static to retain its state throughout multiple calls to bar2() and bar() does not call bar2().

    The first two examples I gave I got an error about undefined reference to Foo::Foo() because the Foo constructor takes three arguments.

    The last example, I get an undefined reference to 'f' error in bar2().
    Last edited by BdON003; 11-22-2009 at 08:23 PM.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by BdON003
    Well that brings me to my original problem then. What I need is to be able to initialize an object in a function ( called void initialize()) and be able to use that object in another function. Taking the third example I gave, the object f must be static to retain its state throughout multiple calls to bar2() and bar() does not call bar2().
    I do not really understand your original problem though. What is the big picture of what you are trying to solve?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Oct 2009
    Posts
    48
    I have a class called IssueQueue. I have a function called initialize() which will read arguments from the command line and initialize an IssueQueue object according to the arguments. I have other functions which then need to use the IssueQueue object that was initialized in initialize().

    I've tried declaring an IssueQueue outside of all functions to make it global but I received an error about no constructor with zero arguments. In my examples in my first post, IssueQueue would be Foo and initialize would be bar, just to show what I have tried so far.

    Passing issue_queue around as an argument seems like a poor design because there are a few classes similar to IssueQueue that I need to do this with. As another reason not to pass it as an argument, all of these functions that use IssueQueue will be called by main and I have no reason to make the IssueQueue object visible to main. All of these functions (except main) will be contained in the same file, though.

    dynamic_scheduler.cpp
    Code:
    IssueQueue issue_queue; //* Error here
    
    void initialize()
    {
        int x;
        ... //* Give a value to x
        issue_queue(x);
    }
    
    void dispatch()
    {
      ...
        Instruction instr = new Instruction(...);
       issue_queue.push(instr);
      ...
    }
    
    void execute()
    {
      ...
       issue_queue.pop();
      ...
    }

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by BdON003
    I've tried declaring an IssueQueue outside of all functions to make it global but I received an error about no constructor with zero arguments.
    Once you have a user defined constructor for IssueQueue, the default constructor will no longer be automatically generated, thus you need to provide it yourself if it is necessary.

    Quote Originally Posted by BdON003
    Passing issue_queue around as an argument seems like a poor design because there are a few classes similar to IssueQueue that I need to do this with.
    That reasoning does not make sense to me. That you have objects of other classes that need to be initialised from command line arguments has no bearing on the decision to pass an object to an initialisation function.

    Quote Originally Posted by BdON003
    As another reason not to pass it as an argument, all of these functions that use IssueQueue will be called by main and I have no reason to make the IssueQueue object visible to main.
    Then you should define another function that calls these functions, and then call that new function from main.

    I think that your initialize function should take the IssueQueue by reference, or perhaps return an IssueQueue object by value (but this will rely on named return value optimisation to be efficient; yet you will not need a default constructor which may be a Good Thing).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Oct 2009
    Posts
    48
    Quote Originally Posted by laserlight View Post
    Once you have a user defined constructor for IssueQueue, the default constructor will no longer be automatically generated, thus you need to provide it yourself if it is necessary.
    I don't want the default constructor called there, I want to say "Hey friendly compiler, I have an object named issue_queue that I will initialize in a few seconds but this is what it looks like". Though if this is really going to be this difficult then I'd rather have a default constructor and an issue_queue.initialize(x) function than passing issue_queue as an argument.

    Quote Originally Posted by laserlight View Post
    That reasoning does not make sense to me. That you have objects of other classes that need to be initialised from command line arguments has no bearing on the decision to pass an object to an initialisation function.
    Again, what I meant was that I have a few objects that would need to be passed around along with issue_queue, and not the same objects each time. This is what I mean:
    Code:
    void initialize(IssueQueue& issue_queue, ROB& rob, DispatchQueue& dispatch_queue, ExecutionList& execution_list, RegFile& reg_file)
    {
        int x;
        ... //* Give a value to x
        issue_queue(x);
    }
    
    void dispatch(IssueQueue& issue_queue, DispatchQueue& dispatch_queue, ExecutionList& execution_list, RegFile& reg_file)
    {
      ...
        Instruction instr = new Instruction(...);
       issue_queue.push(instr);
      ...
    }
    
    void execute(IssueQueue& issue_queue, ROB& rob, ExecutionList& execution_list, RegFile& reg_file)
      ...
       issue_queue.pop();
      ...
    }
    Quote Originally Posted by laserlight View Post
    Then you should define another function that calls these functions, and then call that new function from main.

    I think that your initialize function should take the IssueQueue by reference, or perhaps return an IssueQueue object by value (but this will rely on named return value optimisation to be efficient; yet you will not need a default constructor which may be a Good Thing).
    I would still prefer an issue_queue.initialize() function to doing this do to the large inconsistent number of objects that need to be passed.

    This seems like it should be a basic thing to me, but that could be because I am trying to kick the C habit. Here is what I'd like to have that works with a built-in type:
    Code:
    unsigned int depth;
    
    void initialize()
    {
       int x;
    ...
       depth = x;
    }
    
    void fetch()
    {
      int fetch_depth = depth;
    ...
    }
    I'm pretty sure that works in C++, and it's late but that should work in C, too.
    Last edited by BdON003; 11-22-2009 at 11:27 PM.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by BdON003
    Here is what I'd like to have that works with a built-in type:
    Yes, but objects of built-in types do not have constructors. If they did, this would invoke the default constructor:
    Code:
    unsigned int depth;
    Of course, since you want file scope you would declare the variable as static as in your first post, or maybe define it in an anonymous namespace.

    Quote Originally Posted by BdON003
    I don't want the default constructor called there, though if this is really going to be this difficult then I'd rather have a default constructor and an issue_queue.initialize(x) function than passing issue_queue as an argument.
    So, if you really do want to emulate this for your class type, then you must define a default constructor that does not initialise, and then provide a function for initialisation that is called by the free function initialize(). This is two stage construction.

    twomers' suggestion is viable, but you may need (or at least want) to have another function that destroys the dynamically created object(s), or perhaps use smart pointers.

    Quote Originally Posted by BdON003
    Again, what I meant was that I have a few objects that would need to be passed around along with issue_queue, and not the same objects each time.
    Ah

    Quote Originally Posted by BdON003
    I would still prefer an issue_queue.initialize() function to doing this do to the large inconsistent number of objects that need to be passed.
    The bad part is that when you have variables at file scope, the problems with global variables kick in. It will become harder to maintain this collection of functions. Having to pass the objects is troublesome, but it means that the functions will operate on only those objects that it needs to operate on.

    One possible alternative is to group the objects into an aggregate struct, and then pass that struct object around. However, this may not be much of an improvement. Another possibility is to bite the bullet and use these global variables, but apply the Singleton pattern to ensure that these functions are really only working on the same set of objects.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    The C++ standard provides no portable way to control the initialization of global objects. To achieve what you want to achieve, you can use compiler-specific commands that put the object in a non-initialization segment so that the constructor is suppressed.

    The following is for Visual C++ only:

    Code:
    #pragma warning(push)
    #pragma warning(disable : 4075)
    #pragma init_seg("My-Init_seg")
    
    IssueQueue my_instance;
    
    #pragma warning(pop)
    
    void initialize(...) {
       new (&my_instance) IssueQueue(your_arguments_here);
    }
    Otherwise, you have to use some nasty tricks.

    I'm going to borrow the technique used by STLport to handle standard iostreams construction. What you do is define the global instance with a different type so as to supress the constructor. Something like this, for example:

    Code:
    union fake_issue_queue {
       char buf[sizeof(IssueQueue)]; // May need to introduce some padding
    
       IssueQueue* operator&()
          {
          return(reinterpret_cast<IssueQueue*>(this));
          }
    };
    
    fake_issue_queue my_instance;
    
    void initialize(...) {
       new (&my_instance) IssueQueue(your_arguments_here);
    }
    If not, then you'll have to resort to the alternatives posted here: A heap-allocated instance (Which you must remember to deallocate when your program finishes), or a constructor that doesn't initialize (May not be viable depending on the class design).

  12. #12
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    Changing unsigned int to myTpe shouldn't change the logic. This is feasible:
    Code:
    myType depth;
    
    void initialize()
    {
       myTyp x;
    ...
       depth = x;
    }
    
    void fetch()
    {
       myType fetch_depth = depth;
    ...
    }
    As long as you have define a default constructor and overload the operator =
    You want to initialize the objects inside a function. Initialization has two steps for objects
    1) Allocate memory
    2) Give initial values to member variables

    The 2) can be done with the above code. But the allocation of memory happens outside the function initialize(). As it does with standard types. Is that really a problem? If it is and you want to allocate memory inside the function then there is no other way but with using dynamic allocation, thus new/delete. If it not a problem then just define what you want (the default constructo as suggested) and you are done

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. File transfer- the file sometimes not full transferred
    By shu_fei86 in forum C# Programming
    Replies: 13
    Last Post: 03-13-2009, 12:44 PM
  2. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  3. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  4. Scope And Parameter Passing
    By djwicks in forum C Programming
    Replies: 6
    Last Post: 03-28-2005, 08:26 PM
  5. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM