'Violation thrown when trying to read from binary file

I have a structure with all the data for a contestant. I have a function where I input the value of contestants' data like team name, team hometown, team foundation date and etc. Then I have a function to write that data to a binary file and also a function to read that data from the binary file.

My structure:

struct Team {
    string teamName;
    string teamHometown;
    int foundedDay{};
    int foundedMonth{};
    int foundedYear{};
    int matchPlayed{};
    int matchLost{};
    int goalsFor{};
    int goalsAgainst{};
    int goalDifference{};
    int Points{};
};

My write and read functions:

void writeBinary(Team* T, int& contestantCount) {
    Team Data;
    ofstream File;
    File.open("Data.bin", ios::binary | ios::out);
    if (File.is_open()) {
        File.write(reinterpret_cast<char*>(&Data), sizeof(Team));
        File.close();
        system("cls");
        cout << "|--------------------------------------------------------------------------------------------|" << endl;
        cout << "                            DATA SUCCESSFULLY SAVED TO BINARY FILE" << endl;
        cout << "|--------------------------------------------------------------------------------------------|" << endl << endl;
        system("pause");
    }
    else {
        system("cls");
        cout << "|--------------------------------------------------------------------------------------------|" << endl;
        cout << "                                COULD NOT OPEN BINARY DATA FILE" << endl;
        cout << "|--------------------------------------------------------------------------------------------|" << endl << endl;
        system("pause");
    }
}

void readBinary(Team* T, int& contestantCount) {
    Team Data;
    ifstream File;
    File.open("Data.bin", ios::binary | ios::in);
    if (File.is_open()) {
        File.read(reinterpret_cast<char*>(&Data), sizeof(Team));
        File.close();
        system("cls");
        cout << "|--------------------------------------------------------------------------------------------|" << endl;
        cout << "                             SHOWING SAVED DATA FROM BINARY FILE" << endl;
        cout << "|--------------------------------------------------------------------------------------------|" << endl << endl;
    }
    else {
        system("cls");
        cout << "|--------------------------------------------------------------------------------------------|" << endl;
        cout << "                                COULD NOT OPEN BINARY DATA FILE" << endl;
        cout << "|--------------------------------------------------------------------------------------------|" << endl << endl;
        system("pause");
    }
    cout << Data.teamName << endl;
    system("pause");
}

I assume that my write function works fine since it doesn't give me any violations in the code and I can see that the .bin file is created with the contents in it. When I run the read function though, it gives me this violation and it gives me "Read access violation" in the terminal.

Here is a picture of the result in the console when I run the read function and a picture of the violation that it gives me after the function reaches its end.

Console output screenshotViolation screenshot



Solution 1:[1]

You cannot write the whole struct Team in a fie because std::string may allocate memory. When you are writing std::string and reading it back, the pointers you read will not point to the right place.

Instead, you need to write and read one struct member at a time, and do something special for std::string. The whole exercise is known as serialization. It is not automatic in C++.

Solution 2:[2]

To get the information from the pipes, you can't just use the [_raw_field] since it's not stored that way. It's a little more complicated to get the value of the Piped data. To get the value of the pipes, you have to retrieve the form tags, then loop through the pipe values for each.

add_action( 'wpcf7_before_send_mail', 'dd_handle_form_submission', 10, 3 );
function dd_handle_form_submission( $contact_form, $abort, $submission ) {
    if ( $submission ) {
        $form_data = $submission->get_posted_data();
        // Get the tags.
        $tags = $submission->get_contact_form()->scan_form_tags();
        // Get the country field submission.
        $country = $submission->get_posted_data( 'country' );
        foreach ( $tags as $tag ) {
            if ( 'country' === $tag->name ) {
                // Get the Pipes.
                $pipe_array = $tag->pipes->to_array();
                foreach ( $pipe_array as $value ) {
                    if ( $country[0] === $value[1] ) {
                        // $value[0] is Left of Pipe - $value[1] is right of pipe.
                        $country_name = $value[0];
                    }
                }
            }
        }
        if ( isset( $country_name ) ) {
            $mydb = new wpdb( 'user', 'password', 'database', 'localhost' );
            $mydb->insert(
                'tableName',
                array(
                    'fullname'    => sanitize_text_field( $form_data['FullName'] ),
                    'country'     => $country_name,
                    'companyname' => sanitize_text_field( $form_data['CompanyName'] ),

                ),
                array( '%s', '%s', '%s' )
            );
        }
    }
}

New Answer / Solution to Specific Problem

In your case, the values after the pipes are not unique. This poses another issue all together, which makes pipes less than awesome. In this case, I would use jQuery and a hidden form field.

Make the contact form something like this:

<p>[select* country id:country include_blank "Canada | [email protected],[email protected]" "Mexico | [email protected]" "Serbia | [email protected]" "Zimbabwe | [email protected]"]</p>

<p>[text FullName]</p>
<p>[email your-email]</p>

[hidden hidden_country id:hidden_country]

[submit]

<script>
    jQuery(function($){
        $('#country').on( 'change', function() {
            $('#hidden_country').val($(this).val());
        });
    });
</script>

Then since you're just capturing the country value on change, you can easily push that value to your database, and your email to (the right of the pipes) is used, and that's that.

add_action( 'wpcf7_before_send_mail', 'dd_handle_form_submission', 10, 3 );
function dd_handle_form_submission( $contact_form, $abort, $submission ) {
    if ( $submission ) {
        $form_data = $submission->get_posted_data();
        $country_name = sanitize_text_field( $form_data['hidden_country'] );
        if ( ! empty( $country_name ) ) {
            $mydb = new wpdb( 'user', 'password', 'database', 'localhost' );
            $mydb->insert(
                'tableName',
                array(
                    'fullname'    => sanitize_text_field( $form_data['FullName'] ),
                    'country'     => $country_name,
                    'companyname' => sanitize_text_field( $form_data['CompanyName'] ),

                ),
                array( '%s', '%s', '%s' )
            );
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Eugene
Solution 2