Question

To my knowledge, C++ always evaluates from left to right in a conditional statement

if(A, B, C)

A would be evaluated first, B second, so on. However, the following example is exhibiting some odd behavior.

#include <iostream>
#include <map>
#include <memory>
#include <vector>

#include <boost/logic/tribool.hpp>

//-////////////////////////////////////////////
// File Block
class FileBlock {
public:
    FileBlock();
    virtual ~FileBlock();
    bool linked();

    std::vector<int> messages_;

private:
    boost::logic::tribool position_;
    std::shared_ptr<FileBlock> precedingBlock_ = nullptr;
    std::shared_ptr<FileBlock> followingBlock_ = nullptr;
};

FileBlock::FileBlock()  {
    std::cout << "Breakpoint." << std::endl;

    // "linked()" evaluated first by scope.
    if(linked())    {
        if(!position_
            && precedingBlock_->messages_.back() > 1)   {
                std::cout << "Unreachable." << std::endl;
        }
    }

    // "linked()" evaluated first without the tribool.
    if(linked()
        && precedingBlock_->messages_.back() > 1)   {
            std::cout << "Unreachable." << std::endl;
    }

    // "precedingBlock_->messages_.back() > 1" evaluated first. (Crash because null.)
    if(linked()
        && !position_
        && precedingBlock_->messages_.back() > 1)   {
            std::cout << "Unreachable." << std::endl;
    }
}

FileBlock::~FileBlock() {}

bool FileBlock::linked()    {
    return false;
}

//-////////////////////////////////////////////
// main
int main()  {
    std::shared_ptr<FileBlock> followingBlock(new FileBlock());

    return 0;
}

There are three versions of the conditional in the example. To my knowledge, the first and last should evaluate the same. However, as I trace the program in gdb, when I reach the third version of the conditional, the right most condition is the first to be evaluated.

Scoping the conditional obviously fixes the issue (as demonstrated in the first version of the conditional), as does removing the tribool altogether as demonstrated in the second conditional, but I should be able to use the third one without incident!

The program should kick out and return without doing anything since the left most condition is always false, but this is not the case.

What is up here? Am I not understanding something about tribool? Am I hallucinating?

Here's a inventory of the mingw build I'm using as well as the installed libraries:

Core Inventory:
 - autoconf2.5-2.68-1
 - autoconf-10-1
 - automake1.11-1.11.1-1
 - binutils-2.24-1
 - expat-2.1.0-1
 - gcc-c++-4.8.1-4
 - gcc-core-4.8.1-4
 - gdb-7.6.1-1
 - gettext-0.18.3.1-1
 - gmp-5.1.2-1
 - libiconv-1.14-3
 - libltdl-2.4-1
 - libtool-2.4-1
 - make-3.82.90-2
 - mingwrt-4.0.3-1
 - mpc-1.0.1-2
 - mpfr-3.1.2-2
 - pthreads-w32-2.9.1-1
 - w32api-4.0.3-1
 - wsl_rc-4.0-1
 - zlib-1.2.8-1

Auxiliary Inventory:
 - wxWidgets 3.0.0
 - Boost 1.55
 - yaml-cpp 0.5.1

Here are my build commands:

g++ -std=gnu++11 -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\main.o" "..\\src\\main.cpp" 
g++ -o wtf.exe "src\\main.o" 
Was it helpful?

Solution

Unlike built-in logical operators, overloaded logical operators (and they are overloaded for boost::tribool) don't have left-to-right order of evaluation (nor short-circuit semantics). The order of evaluation of operands is unspecified like almost everywhere else.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top