Solved

Help understanding scope issue

Posted on 2014-10-14
9
179 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
  • 4
  • 3
  • 2
9 Comments
 
LVL 30

Accepted Solution

by:
Zoppo earned 300 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 200 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
 
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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 30

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 200 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 30

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 30

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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
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.

705 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now