Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Segmentation fault in std::transform

I'm trying to transfer parsed out the file names from regex match to the list of filesystem::path objects.

I believe that matches are valid because for_each for the same iterators and print to console work perfectly. However, I'm getting a segmentation fault running this code. What am I doing wrong? Is there a mistake in my lambda?

        namespace fs = boost::filesystem;
        std::forward_list<fs::path> results;
        std::transform(std::sregex_iterator(file_data.begin(), file_data.end(), re),
                       std::sregex_iterator(), results.begin(),
                       [&](const std::smatch& m)->fs::path{
            return root / fs::path(m[1].str());
        });

GDB shows me this line as a place of error:

path& operator=(const path& p)
{
  m_pathname = p.m_pathname;
  return *this;
}

UPDATE: found the solution - use back_inserter(results) instead of results.begin(). However, why is that?

like image 594
amigo421 Avatar asked Jun 24 '15 19:06

amigo421


People also ask

How do you resolve a segmentation fault in C++?

Compile your application with -g , then you'll have debug symbols in the binary file. Use gdb to open the gdb console. Use file and pass it your application's binary file in the console. Use run and pass in any arguments your application needs to start.

What causes segmentation fault in C++?

Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.” When a piece of code tries to do read and write operation in a read only location in memory or freed block of memory, it is known as core dump. It is an error indicating memory corruption.

What does std :: transform do?

std::transform applies the given function to a range and stores the result in another range, keeping the original elements order and beginning at d_first. 1) The unary operation unary_op is applied to the range defined by [first1, last1) .

What is segmentation fault with example?

A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).


2 Answers

Your output iterator is a simple results.begin(), which is probably == results.end(). The clue here is that the failure comes when trying to assign the result.

You either need a back_inserter as you found, or to use some container with enough space already allocated (which can only work if you know how many items you're transforming in advance).

Specifically, consider the sample implementation of the first overload here.

The line

*d_first++ = op(*first1++);

requires the destination iterator already to be valid. If it's == end() as suggested, the whole operation is illegal.

like image 142
Useless Avatar answered Oct 19 '22 00:10

Useless


The std::transform algorithm's third parameter should be an iterator to the start of the range where the values should be written. Specifically, it works by overwriting the values in the range pointed at by the iterator with the transformed values. This means that there actually have to be values there to overwrite in the first place. In your case, you're writing to an empty forward_list, so there's nothing to write to, hence the crash.

To fix this, consider replacing the last argument with a back_inserter, which will automatically create the space that's needed as the values are produced:

std::transform(std::sregex_iterator(file_data.begin(), file_data.end(), re),
               std::sregex_iterator(),
               back_inserter(results), // <--- This is new
               [&](const std::smatch& m)->fs::path{
        return root / fs::path(m[1].str());
});

More generally, to the best of my knowledge, all of the algorithms in <algorithm> that write to output ranges will assume that there are values available to overwrite in that range. If that isn't the case, consider using a back_inserter or other type of insert iterator, which will automatically create the space that's needed for you.

Hope this helps!

like image 38
templatetypedef Avatar answered Oct 19 '22 01:10

templatetypedef