Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Help understanding scope issue

Posted on 2014-10-14
9
Medium Priority
?
199 Views
Last Modified: 2014-10-14
If have this bit of code that invokes a web server and works fine:

void  main(){
    const char * options[] = { "document_root", DOCUMENT_ROOT,
        "listening_ports", PORT, 0
    };
    CivetServer server(options);
    while (!exitNow) {
      Sleep(1000);
    }
}

However, I'd like to move the part that starts the "Civetserver" out into another function, just to separate it out, like this:

void main(){
    initialize();
    while (!exitNow) {
      Sleep(1000);
    }
}
void initialize(){
    const char * options[] = { "document_root", DOCUMENT_ROOT,
        "listening_ports", PORT, 0
    };
    CivetServer server(options);
}

This works while we are inside the function "initialize". But it appears that whenever I leave the "initialize" function, the var "server" is gone, I guess destroyed because it's not in scope?

Trying to get around this, I also tried this, and it had the same result, but I'm not sure why.
void main(){
    CivetServer server = initialize();
    while (!exitNow) {
      Sleep(1000);
    }
}
CivetServer initialize(){
    const char * options[] = { "document_root", DOCUMENT_ROOT,
        "listening_ports", PORT, 0
    };
    CivetServer server(options);
    return server;
}

I'm a newb and probably just have some fundamental misunderstanding of what I'm doing here.
0
Comment
Question by:rustycp
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 2
9 Comments
 
LVL 31

Accepted Solution

by:
Zoppo earned 1200 total points
ID: 40380636
Hi rustycp,

this depends on how the CivetServer is implemented. If it's a class which can safely be copied using assignment operator or copy constructor your second approach can work. The first approach can't really work since you use server as a function-local variable which is destroyed when it falls out from scope when the initialize function exits.

In case it's not possible to use your second approach (i.o.w. if the object can't be copied safely and if there's no other way to create a complete instance than calling the constructor) easiest is to use a pointer, i.e.
void main(){
    CivetServer* pServer = initialize();
    while (!exitNow) {
      Sleep(1000);
    }
   delete pServer; // clean up
}
CivetServer initialize(){
    const char * options[] = { "document_root", DOCUMENT_ROOT,
        "listening_ports", PORT, 0
    };
    return new CivetServer(options);
}

Open in new window

Hope this helps,

ZOPPO
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 800 total points
ID: 40380646
Your 'CivetServer' instance is a local variable to 'initialize()', so it will be destroyed as soon as the function exits (see e.g. http://www.tutorialspoint.com/cplusplus/cpp_variable_scope.htm). You are quite close in your 2nd example, but if the class does not have a copy constructor and assignment operator, you might not be able to return it from your function.

The basic ide here would be to use a 'CivetServer*' and create the instance dynamically like

void main(){
    CivetServer* server = initialize();
    while (!exitNow) {
      Sleep(1000);
    }
   terminate(server);
}
CivetServer* initialize(){
    const char * options[] = { "document_root", DOCUMENT_ROOT,
        "listening_ports", PORT, 0
    };
    CivetServer* server = new CivetServer(options);
    return server;
}
void terminate(CivetServer* server) {

  delete server;
}

Open in new window

0
 
LVL 2

Author Comment

by:rustycp
ID: 40380665
Hm I see the direction depends on the class... here is the exact class. The docs tell me that this actually starts the server:

CivetServer server(options);



/**
 * CivetServer
 *
 * Basic class for embedded web server.  This has an URL mapping built-in.
 */
class CivetServer
{
public:

    /**
     * Constructor
     *
     * This automatically starts the sever.
     * It is good practice to call getContext() after this in case there
     * were errors starting the server.
     *
     * @param options - the web server options.
     * @param callbacks - optional web server callback methods.
     */
    CivetServer(const char **options, const struct mg_callbacks *callbacks = 0);

    /**
     * Destructor
     */
    virtual ~CivetServer();

    /**
     * close()
     *
     * Stops server and frees resources.
     */
    void close();

    /**
     * getContext()
     *
     * @return the context or 0 if not running.
     */
    const struct mg_context *getContext() const {
        return context;
    }

    /**
     * addHandler(const std::string &, CivetHandler *)
     *
     * Adds a URI handler.  If there is existing URI handler, it will
     * be replaced with this one.
     *
     * URI's are ordered and prefix (REST) URI's are supported.
     *
     *  @param uri - URI to match.
     *  @param handler - handler instance to use.  This will be free'ed
     *      when the server closes and instances cannot be reused.
     */
    void addHandler(const std::string &uri, CivetHandler *handler);

    /**
     * removeHandler(const std::string &)
     *
     * Removes a handler.
     *
     * @param uri - the exact URL used in addHandler().
     */
    void removeHandler(const std::string &uri);

    /**
     * getCookie(struct mg_connection *conn, const std::string &cookieName, std::string &cookieValue)
     *
     * Puts the cookie value string that matches the cookie name in the cookieValue destinaton string.
     *
     * @param conn - the connection information
     * @param cookieName - cookie name to get the value from
     * @param cookieValue - cookie value is returned using thiis reference
     * @returns the size of the cookie value string read.
    */
    static int getCookie(struct mg_connection *conn, const std::string &cookieName, std::string &cookieValue);

    /**
     * getHeader(struct mg_connection *conn, const std::string &headerName)
     * @param conn - the connection information
     * @param headerName - header name to get the value from
     * @returns a char array whcih contains the header value as string
    */
    static const char* getHeader(struct mg_connection *conn, const std::string &headerName);

    /**
     * getParam(struct mg_connection *conn, const char *, std::string &, size_t)
     *
     * Returns a query paramter contained in the supplied buffer.  The
     * occurance value is a zero-based index of a particular key name.  This
     * should not be confused with the index over all of the keys.  Note that this
     * function assumes that parameters are sent as text in http query string
     * format, which is the default for web forms. This function will work for
     * html forms with method="GET" and method="POST" attributes. In other cases,
     * you may use a getParam version that directly takes the data instead of the
     * connection as a first argument.
     *
     * @param conn - parameters are read from the data sent through this connection
     * @param name - the key to search for
     * @param dst - the destination string
     * @param occurrence - the occurrence of the selected name in the query (0 based).
     * @return true if key was found
     */
    static bool getParam(struct mg_connection *conn, const char *name,
                         std::string &dst, size_t occurrence=0);

    /**
     * getParam(const std::string &, const char *, std::string &, size_t)
     *
     * Returns a query paramter contained in the supplied buffer.  The
     * occurance value is a zero-based index of a particular key name.  This
     * should not be confused with the index over all of the keys.
     *
     * @param data - the query string (text)
     * @param name - the key to search for
     * @param dst - the destination string
     * @param occurrence - the occurrence of the selected name in the query (0 based).
     * @return true if key was found
     */
    static bool getParam(const std::string &data, const char *name,
                         std::string &dst, size_t occurrence=0) {
        return getParam(data.c_str(), data.length(), name, dst, occurrence);
    }

    /**
     * getParam(const char *, size_t, const char *, std::string &, size_t)
     *
     * Returns a query paramter contained in the supplied buffer.  The
     * occurance value is a zero-based index of a particular key name.  This
     * should not be confused with the index over all of the keys.
     *
     * @param data the - query string (text)
     * @param data_len - length of the query string
     * @param name - the key to search for
     * @param dst - the destination string
     * @param occurrence - the occurrence of the selected name in the query (0 based).
     * @return true if key was found
     */
    static bool getParam(const char *data, size_t data_len, const char *name,
                         std::string &dst, size_t occurrence=0);


    /**
     * urlDecode(const std::string &, std::string &, bool)
     *
     * @param src - string to be decoded
     * @param dst - destination string
     * @param is_form_url_encoded - true if form url encoded
     *       form-url-encoded data differs from URI encoding in a way that it
     *       uses '+' as character for space, see RFC 1866 section 8.2.1
     *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
     */
    static void urlDecode(const std::string &src, std::string &dst, bool is_form_url_encoded=true) {
        urlDecode(src.c_str(), src.length(), dst, is_form_url_encoded);
    }

    /**
     * urlDecode(const char *, size_t, std::string &, bool)
     *
     * @param src - buffer to be decoded
     * @param src_len - length of buffer to be decoded
     * @param dst - destination string
     * @param is_form_url_encoded - true if form url encoded
     *       form-url-encoded data differs from URI encoding in a way that it
     *       uses '+' as character for space, see RFC 1866 section 8.2.1
     *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
     */
    static void urlDecode(const char *src, size_t src_len, std::string &dst, bool is_form_url_encoded=true);

    /**
     * urlDecode(const char *, std::string &, bool)
     *
     * @param src - buffer to be decoded (0 terminated)
     * @param dst - destination string
     * @param is_form_url_encoded true - if form url encoded
     *       form-url-encoded data differs from URI encoding in a way that it
     *       uses '+' as character for space, see RFC 1866 section 8.2.1
     *       http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
     */
    static void urlDecode(const char *src, std::string &dst, bool is_form_url_encoded=true);

    /**
     * urlEncode(const std::string &, std::string &, bool)
     *
     * @param src - buffer to be encoded
     * @param dst - destination string
     * @param append - true if string should not be cleared before encoding.
     */
    static void urlEncode(const std::string &src, std::string &dst, bool append=false) {
        urlEncode(src.c_str(), src.length(), dst, append);
    }

    /**
     * urlEncode(const char *, size_t, std::string &, bool)
     *
     * @param src - buffer to be encoded (0 terminated)
     * @param dst - destination string
     * @param append - true if string should not be cleared before encoding.
     */
    static void urlEncode(const char *src, std::string &dst, bool append=false);

    /**
     * urlEncode(const char *, size_t, std::string &, bool)
     *
     * @param src - buffer to be encoded
     * @param src_len - length of buffer to be decoded
     * @param dst - destination string
     * @param append - true if string should not be cleared before encoding.
     */
    static void urlEncode(const char *src, size_t src_len, std::string &dst, bool append=false);

protected:
    class CivetConnection {
    public:
        char * postData;
        unsigned long postDataLen;

        CivetConnection();
        ~CivetConnection();
    };

    struct mg_context *context;
    std::map<struct mg_connection *, class CivetConnection> connections;

private:
    /**
     * requestHandler(struct mg_connection *, void *cbdata)
     *
     * Handles the incomming request.
     *
     * @param conn - the connection information
     * @param cbdata - pointer to the CivetHandler instance.
     * @returns 0 if implemented, false otherwise
     */
    static int requestHandler(struct mg_connection *conn, void *cbdata);

    /**
     * closeHandler(struct mg_connection *)
     *
     * Handles closing a request (internal handler)
     *
     * @param conn - the connection information
     */
    static void closeHandler(struct mg_connection *conn);

    /**
     * Stores the user provided close handler
     */
    void (*userCloseHandler)(struct mg_connection *conn);

};
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Author Comment

by:rustycp
ID: 40380672
I was originally thinking the class was a singleton, but then I wouldn't understand why it gets destroyed when I leave the initialize function. I guess the issue is that I don't understand how it is implemented, like you said.
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 40380673
Well, there's no copy constructor and nor assignment operator, so since pointers are used in the class (struct mg_context *context;) and because it IMO even is very uncommon to have copyable objects which act as some kind of server I think you should use my or jkr's suggested code.

Best regards,

ZOPPO
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 800 total points
ID: 40380680
Yes, ist seems that thre is no way to copy the server as in your 1st approach. Funny enough, Zoppy and I came up with exactly the same idea to fix it :-D
0
 
LVL 2

Author Comment

by:rustycp
ID: 40380752
To make sure I'm understanding this, in the original code this line:

      CivetServer server(options);

"server" would be a CivetServer instance

and in the new code:

CivetServer* server = new CivetServer(options);

"server" would be a pointer to that CivetServer instance.

In my code, there are places that I called some functions on the "server" object using the dot notation. Like server.addHandler().  With this change, would I now change those calls to be server->addHandler(), since I am calling a function on a pointer to an object. Am I right?
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 40380769
Yes, both is right, instead of an instance you use a pointer to an instance and therefor you have to use '->' as dereferencing operator instead of '.'
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 40380785
BTW, if you really want to you could keep your other code mostly untouched using a reference (allthough it's possibly a bit dnageruous, see last comment in the code fragments below), i.e.:

CivetServer* pServer = new CivetServer(options);

// before calling next line you should check pServer is not NULL, otherwise next line would crash
CivetServer& server = *pServer;
...
server.addHandler(); // works the same as before.

When you want to call other functions which do something with this instance you can either pass it by pointer ot by reference, i.e.

void foo ( CivetServer* pServer )
{
 pServer->do_something();
}

void bar( CivetServer& server )
{
 server.do_something();
}

void foobar()
{
 CivetServer* pServer = new CivetServer(options);
 foo( pServer );

 CivetServer& server = *pServer;
 bar( server );

 delete pServer;
 // WARNING: Don't use 'server' after this again coz it will lead to runtime errors and most probably a crash.
}

ZOPPO
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

704 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question