dup2

Discussion in 'C++' started by Hongliang Wang, Apr 22, 2014.

  1. Hell all,

    I was trying to redirect stdout to a file by using dup2. First I followed microsoft example: http://msdn.microsoft.com/en-us/library/8syseb29.aspx

    it just works fine.

    Then I tried to implement this in my own class (ABCLog) but stdout is not captured. I cannot figure it out. The only reason I could think of is that main() is in main.cpp while class ABCLog are in separate files (ABCLog.cpp and ABCLog.h). Could anybody confirm this please?

    int main(int argc, char *argv[])
    {
    ABCLog *log = new ABCLog();

    puts("in main");
    fflush( stdout );

    delete log;

    return 0;
    }

    ABCLog::ABCLog(const char *logFileName)
    {
    old = _dup(1); /* "old" refers to stdout */
    if(old == -1) {
    perror(ERR_000104_DUP);
    exit(1);
    }

    if( fopen_s( &logFile, logFileName, "a" ) != 0 ) {
    fprintf(stderr, ERR_000105_LOG_FILE_OPEN, logFileName);
    exit( 1 );
    }

    if( -1 == _dup2( _fileno( logFile ), 1 ) ) {
    perror( ERR_000106_DUP2 );
    exit( 1 );
    }

    puts("in ABCLog");
    fflush(stdout);
    }

    /**
    * Destructor
    */
    ABCLog::~ABCLog()
    {
    _dup2( old, 1 );
    _flushall();
    m_stream.close();
    }
     
    Hongliang Wang, Apr 22, 2014
    #1
    1. Advertisements

  2. Is this constructor ever called? Your dynamic allocation does not
    specify an argument that matches this parameter list.
     
    Barry Schwarz, Apr 22, 2014
    #2
    1. Advertisements

  3. Yes, the constructor is being called because there is only one declaration as follows:

    ABCLog(const char *logFileName = "log.txt");
     
    Hongliang Wang, Apr 23, 2014
    #3
  4. That line of code does not exist in your original post.
     
    Barry Schwarz, Apr 23, 2014
    #4
  5. Hongliang Wang

    Paul N Guest

    Other people have explained this, but perhaps not clearly enough, so I'll have a go.

    In main, the object is brought into existence, but it then is destroyed without the program doing anything to it. Strange as it may seem, this means that the compiler is allowed to not create the object at all. So you don't get the side effects from the constructor and the destructor that you were hoping for.

    So - is the constructor actually being run? You could test this for exampleby putting an output command or a beep into the constructor - does the computer actually beep when you run it?

    From your last reply, it seems that you are answering the question of whether the constructor runs simply by looking at the code and saying "but surely it must do?" Don't do that - actually test it.

    Hope this helps.
    Paul.
     
    Paul N, Apr 23, 2014
    #5
  6. Hongliang Wang

    Guest

    do{
    assert(!pendingTransactions.empty());
    auto const& request=*pendingTransactions.front();
    if(cmwBuf.GiveBool()){
    setDirectory(request.path.c_str());
    empty_container<File>{cmwBuf};
    save_lastruntime(request.filename_with_extension.c_str()
    ,request.latest_update);
    middle_messages_front::Marshal(localsendbuf,true);
    }else
    middle_messages_front::Marshal(localsendbuf,false
    ,cmwBuf.GiveCharStar());
    localsendbuf.Flush((sockaddr*)&request.front_tier
    ,sizeof(request.front_tier));
    pendingTransactions.pop_front();
    }while(cmwBuf.NextMessage());


    The empty_container there is just constructed. Gcc and Clang
    both keep the ctor in at least from what I can tell.

    I think it'd be lame to have to add a no-op function and
    call it just to keep the compiler from removing the ctor.


    Brian
    Ebenezer Enterprises - In G-d we trust.
    http://webEbenezer.net
     
    , Apr 24, 2014
    #6
  7. Hongliang Wang

    Jorgen Grahn Guest

    Huh? Then how can the pattern with RAII mutex locks work?

    void foo()
    {
    Lock lock(some_mutex);
    do_stuff_that_needs_locking();
    }

    I've always assumed the compiler must obey (create 'lock', and do it
    before calling the other function) in this case, not take a chance on
    the constructor having no side effects. (Modulo the as-if rule, of
    course.)

    (I'm vaguely aware that copy construction is a special case and that
    it's a Bad Idea to treat that one as any other function.)

    /Jorgen
     
    Jorgen Grahn, Apr 24, 2014
    #7
  8. Hongliang Wang

    David Brown Guest

    It all depends on observable effects - accessing volatiles, calls to
    externally defined functions, exiting the program, and inline assembly.
    If the compiler knows for sure that a particular expression (including
    the construction of an object) does not have any influence on the
    observable effects of the program, then it can remove that expression.
    And if that means all actions on a variable is removed, then the
    variable can be removed.

    But if the compiler is in any doubt about the observable effects, then
    it needs to generate the code in the order guaranteed to follow those
    observable effects. So if Lock's constructor has such effects (and it
    almost certainly will, to be of much use), then your lock gets created.
    And if do_stuff_that_needs_locking() has any such effects (ant it
    almost certainly will, or you wouldn't need the lock), it happens after
    the Lock is created and before it is destroyed.

    It is possible for things to be re-arranged, however. If you had this:

    int protectedData;
    static void do_stuff_that_needs_locking() {
    int x = 0;
    for (int i = 0; i < 1000; i++) {
    x += i;
    }
    protectedData = x;
    }

    Then the compiler /could/ generate this:

    void foo() {
    int x = 0;
    for (int i = 0; i < 1000; i++) {
    x += i;
    }
    Lock lock(some_mutex);
    protectedData = x;
    // Destruct lock
    }
     
    David Brown, Apr 24, 2014
    #8
  9. Hongliang Wang

    Jorgen Grahn Guest

    Sure. My brain files all that under "as if", especially in C++98's
    memory model.

    So I suppose you implicitly agree with me, that Paul N's explanation
    above is incorrect, given that the OP's constructor was full of
    observable effects? That's mainly what I want to establish.

    /Jorgen
     
    Jorgen Grahn, Apr 24, 2014
    #9
  10. Hongliang Wang

    David Brown Guest

    Yes, I agree with you - and I agree it is all "as if". I really wanted
    to point out that "as if" allows things to be split up and moved around
    in the manner shown above - that catches many people out. (It will not
    normally affect the correctness of your code, unless you are doing
    something odd and haven't taken appropriate measures to control the
    order of the code, but it can be a surprise during debugging or
    examining the object code.)
     
    David Brown, Apr 24, 2014
    #10
  11. Hongliang Wang

    Jorgen Grahn Guest

    True. And your example above /did/ frighten me for a few seconds.
    Then I was relieved to see that it fit in my mental model after all,
    which was nice.

    /Jorgen
     
    Jorgen Grahn, Apr 25, 2014
    #11
  12. Hongliang Wang

    James Kanze Guest

    In main, the object is created with a new expression. The
    compiler is *not* allowed to suppress this.

    Using a local variable would, of course, be more idiomatic (and
    correspond to the widely used RAII idiom).
     
    James Kanze, Apr 28, 2014
    #12
  13. Yes I am sure that constructor is called, because a new file 'log.txt' is being created.

    I have two test messages, one is in main and another one is in class constructor. But 'log.txt' is unable to capture either of them:- its length is zero.
     
    Hongliang Wang, Apr 29, 2014
    #13
  14. Hongliang Wang

    red floyd Guest

    Mixing file descriptors and iostreams (or stdio) can often lead to
    counterintuitve results. That's why the C library has freopen().
    Use that, instead of dup/dup2.

    Alternatively, use IOStreams, and create a new streambuf for
    the log file, and assign that to std::cout.
     
    red floyd, Apr 29, 2014
    #14
  15. Thank you red. freopen works.
     
    Hongliang Wang, Apr 30, 2014
    #15
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.