0

I want to create a global variable called process without assigning anything to it in a first moment. Later on I'll spawn a new process in the operating system, and assign it to that variable.

It can be done in C# like so:

class TestCS
    {
        // creating a variable
        private System.Diagnostics.Process process;

        private void SomeMethod()
        {
            // assigning a newly spawned process to it
            process = Process.Start("file.exe", "-argument");
            process.WaitForInputIdle();
        }       
    }


I wrote the code below to accomplish the same thing with C++. The process variable is of type child (from Boost::Process v0.31). #includes are omitted for simplicity.

Test.hpp

class Test
{
public: 
    void SomeFunction();
private:
    std::string testString; // declaring a test string

    static const std::string program_name;
    static const std::vector<std::string> program_args;
    boost::process::child process;  // attempting to declare a variable of type 'boost::process::child'
};

Test.cpp

void Test::SomeFunction()
{
    testString = "abc"; // I can successfully define the test variable on this line
    std::cout << testString;

    boost::process::context ctxt;

    // the same goes for the next two variables
    const std::string program_name = "startme.exe";
    const std::vector<std::string> program_args = {"/test"};

    // and I want to define the process variable here as well...
    process = boost::process::launch(program_name, program_args, ctxt);
}

Main.cpp

int main()
{
    Test test1;
    test1.SomeFunction();

    cin.get(); // pause
    return 0;
}

However, it returns the following error for Test.cpp:

error C2512: 'boost::process::child' : no appropriate default constructor available


How can it be done correctly?

Marc.2377
  • 7,807
  • 7
  • 51
  • 95
  • Everything that you call declarations in your code are actually definitions. – Anton Savin Oct 13 '14 at 22:07
  • You need to call the constructor of `boost::process::child` in the `initialization list` of `TestClass::TestClass` – Neil Kirk Oct 13 '14 at 22:07
  • @AntonSavin can you elaborate? – Marc.2377 Oct 13 '14 at 22:21
  • why people coming from C# have problems using C++ but not viceversa? – CoffeDeveloper Oct 14 '14 at 08:41
  • 1
    I guess that's because you program for a framework in C#, which has a huge set of built-in classes (for handling the filesystem, database access, internet comms, etc), and also has typical facilitators of a high-level language (automatic garbage collection, etc). Hence we can say it's an "easier" language. – Marc.2377 Oct 14 '14 at 20:22

1 Answers1

2

As the error states, 'boost::process::child' no appropriate default constructor available. This means that the child object must be constructed with a constructor that takes arguments.

Take the following example class

class Foo
{
    Foo(); // This is the _default_ constructor.
    Foo(int i); // This is another constructor.
};

Foo f; // The `Foo();` constructor will be used _by default_. 

If we change that class to the following:

class Foo
{
    Foo(int i); // This is the constructor, there is no default constructor declared.
};

Foo f; // This is invalid.
Foo f(1); // This is fine, as it satisfies arguments for `Foo(int i);

The reason your string is constructed is because it provides a default constructor (which is an empty string), while the process::child class does not.

Therefore, you need to initialize you process::child object when it's constructed. Since it's a part of TestClass (and not a pointer or a reference), it needs to be constructed when the TestClass object is constructed.

Test::Test()
    : process() // Initialize the member here, with whatever args.
{
    SomeFunction();
}

Or...

class Test
{
    // Make it a pointer.
    boost::process::child* pProcess;
};

Test::Test()
{
    pProcess = new boost::process::child(); // And allocate it whenever you want.
    SomeFunction();
}
Marc.2377
  • 7,807
  • 7
  • 51
  • 95
Aesthete
  • 18,622
  • 6
  • 36
  • 45
  • Thanks for your answer. Why is it that I need to manually initialize `process`, but not the string? – Marc.2377 Oct 13 '14 at 22:30
  • I've made some changes that should help explain it. – Aesthete Oct 13 '14 at 23:32
  • because the string is implicitly a pointer (as if it was created with new but no need to delete.. oh yeah you have to delete pProcess in destructor.. you have to do finalization in C++ too) – CoffeDeveloper Oct 14 '14 at 09:01
  • 1
    @DarioOO - Umm no.. The string is _not_ implicitly a pointer. It's a part of `TestClass` and space is allocated for it when the `TestClass` object is created. It just has a _default constructor_ `std::string()` which takes no arguments. – Aesthete Oct 14 '14 at 09:49
  • Great answer, I'm accepting it for my question. I've accomplished my goal using the pointer solution, but would you mind having a look at my additional question (at the end)? I belive that's not possible, just want to be sure. – Marc.2377 Oct 14 '14 at 21:01
  • If you want to make it reference another `process`, declare it like so: `boost::process::child& process`. Then initialize it in the initializer list `TestClass::TestClass(const boost::process::child& otherProcess) : process(otherProcess) {}` – Aesthete Oct 15 '14 at 01:16