Recessive
Recessive

Reputation: 1929

Declare a global variable without initialising in c++

Say I have a header file:

class.h

#pragma once
#include <iostream>
#include <string>
using namespace std;

class my_class
{
private:
    string var1;
public:
    my_class(string var1_val) { var1 = var1_val; };
};

I wish to declare a my_class variable as a global so it can be used across functions. However, it cannot be initialised outside the main function, as it requires user input to initialise. This poses a problem, as if the below code is run, I get: 'my_class': no appropriate default constructor available

source.cpp

#include <iostream>
#include <string>
#include "classes.h"
using namespace std;

my_class f;

int main(){
    string inpt;
    cout << "Enter var1 value: ";
    cin >> inpt;
    f = my_class(inpt);
}

How would I define the variable f so I could initialise it in main, but also use it in another function in the source.cpp file?

Upvotes: 0

Views: 1026

Answers (4)

6502
6502

Reputation: 114461

That is not directly possible... a global class instance requires initialization (only types like int or double can be left initialized, but only in local scopes - as global they're always initialized - and this possibility of leaving variables uninitialized is also something many think is a design error of the C++ language - most younger languages do not provide this option as experience taught us that it's a source of nasty bugs and provides no real advantage).

What you want to do could be interpreted as a variation on what is normally called the "singleton pattern" ... i.e. providing all the modules access to a single instance of a class.

This in C++ is normally done using a function that returns a reference to the variable... for example:

------------------------------------------------------------ parms.h
...
struct Parms {
    std::string user_name;
    int user_age;
    static Parms& get();   // Providing access to the singleton
};

-------------------------------------------------------- module1.cpp
#include "parms.h"
...
void foo() {
    // access the singleton
    std::cout << "Hello " << Parms::get().user_name << "\n";
}

---------------------------------------------------------- parms.cpp
#include "parms.h"
...

static Parms* parmsp;

void init_parms(const std::string& user_name, int user_age) {
    // creates the singleton
    parmsp = new Parms{user_name, user_age};
}

Parms& Parms::get() {
    // Provide access to the singleton
    if (!parmsp) {
        throw std::runtime_error("Parameters not yet initialized");
    }
    return *parmsp;
}

Upvotes: 0

YePhIcK
YePhIcK

Reputation: 5856

There are a few things mixed in the question. I'll try to address them individually.


The error message about the default constructor is exactly that: you are asking to instantiate an instance of that class but you only provide one way of doing so: the constructor with a string parameter.

Two ways you can deal with that "directly":

  1. provide a default constructor, by either having it explicitly or making the string parameter optional, like my_class(string var1_val = {})
  2. provide the said parameter at a time of instantiation: my_class f{""};

Have a variable "outside" in the global scope but initialized in main()... Also, a few ways to deal with that (personally I would advise against such a practice for various reasons, but providing options here for completeness):

  1. Use pointers. Declare your variable as my_class * f{nullptr}; or, even better, as a smart pointer: std::unique_ptr<my_class> f; and instantiate the object in your main as either a naked pointer f = new my_class("string"); or a smart pointer f = std::make_unique<my_class>("args");
  2. have that variable local to main() and pass it into whatever function you need it in

You might also look into using a Singleton Pattern where you have a factory function that manages your f (again, a horrible idea in this case, but providing it for completeness):

my_class & get_my_class(string s = {}){
  static my_class * mc{nullptr};
  if(!mc){ mc = new my_class{s}; } // <-- memory leak here unless you use unique_ptr
  return *mc;
}

int main(){
  // ... 
  auto & m{get_my_class("user input")};
  // ... 
}

void other_function(){
  auto & f{get_my_class()};
  // use f
}

Upvotes: 2

Vishal Chovatiya
Vishal Chovatiya

Reputation: 99

Just do this

my_class(string var1_val="") { var1 = var1_val; };

Provide default argument & you are good to go. Just to get the compiler to shut up. Although using global object is not a good solution.

Upvotes: 0

GoRo3
GoRo3

Reputation: 161

The problem that you describe

as if the below code is run, I get: 'my_class': no appropriate default constructor available

is because you have declare another constructor with some parameter. In this case, compiler will not generate default constructor. You have to do it by yourself. so the class should look like:

    class my_class
{
private:
    string var1;
public:
    my_class(){};
    explicit my_class(string var1_val) : 
    var1(var1_val)
    {};
};

Good practice is when you are making constructor with one argument mark it as explicit. Another good practice is to assign variables in constructor initialization list.

Best Regards

Upvotes: 0

Related Questions