Sign in to follow this  
3dmodelerguy

Access Violation?

Recommended Posts

I have the following code from the building a scripting language tutorial:
#include <iostream>
#include <conio.h>
#include <vector>
#include <assert.h>

enum opcode{op_talk, op_end, op_print};

class instruction
{
        public:
                instruction(opcode code) : _code(code), _data(0) {}
                instruction(opcode code, const char* data, size_t data_size) : _code(code), _data(new char[data_size])
                {
                        memcpy(_data, data, data_size);
                }
                ~instruction()  { delete[] _data; }
                opcode code() const { return _code; }
                const char* data() const    { return _data; }

        private:
                opcode _code;
                char* _data;
};

class script
{
        public:
                script(const std::vector<instruction> &instruction_list) : _instruction_list(instruction_list){}
                const instruction* instruction_pointer() const { return &_instruction_list[0]; }
        private:
                std::vector<instruction> _instruction_list;
};

class virtual_machine
{
        public:
                virtual_machine() : _script_pointer(0), _instruction_pointer(0), _instruction(0), _script_count(0) {}
                
                // a very basic interface
                inline void execute(size_t script_id);
                size_t load(const script& script)   { return add_script(script); }
                
        private:  // useful abstractions
                typedef const script* script_reference;
                typedef const instruction*  instruction_reference;
                // pointers used as non-modifying dynamic references
                private:  // utilities
                size_t add_script(const script& script) // add script to list and retrieve id
                {
                                _script_list.push_back(script);
                                return _script_count++;
                }
                void select_script(size_t index)    // set current script by id
                {
                        assert(index < _script_count);  // make sure the id is valid
                        _script_pointer = &_script_list[index];
                        _instruction_pointer = _script_pointer->instruction_pointer();
                } 

        private:  // data members
                std::vector<script> _script_list;
                script_reference _script_pointer;    // current script
                instruction_reference _instruction_pointer;     // root instruction
                instruction_reference _instruction;        // current instruction
                size_t _script_count;  // track the loaded scripts
};

void virtual_machine::execute(size_t script_id)
{
        select_script(script_id);  // select our _instrPtr by script ID
        _instruction = _instruction_pointer;      // set our iterator to the beginning
        while (_instruction)
        {
                switch(_instruction->code())
                {
                        case op_talk:
                                std::cout << "I am talking." << std::endl;
                                ++_instruction;  // iterate
                                break;

                        case op_print:
                                //std::cout << _instruction->data() << std::endl;
                                ++_instruction;  // iterate
                                break;

                        case op_end:
                                _instruction = 0;  // discontinue the loop
                                break;
                }
        }
}

int main()
{
        virtual_machine vm;

        char* buffer = "this is printed data";

        // build the script
        std::vector<instruction> instruction_list;
        instruction_list.push_back(instruction(op_talk)); // talk twice
        instruction_list.push_back(instruction(op_print, buffer, strlen(buffer) + 1));
        instruction_list.push_back(instruction(op_talk)); // talk twice
        instruction_list.push_back(instruction(op_end));  // then end
        //script script(instruction_list);

        // load the script and save the id
        //size_t script_id = vm.load(script);

        // execute the script by its id
        //vm.execute(script_id);
        _getch();
}



but when I run this I get a access violation reading location, anyone know why since the code it pretty much the same as the tutorial as of right now? [Edited by - 3dmodelerguy on May 5, 2008 10:03:47 PM]

Share this post


Link to post
Share on other sites
Probably because your instruction class doesn't obey the rule of three. In particular, you're lacking a valid copy constructor and assignment operator.

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy
I have the following code from the building a scripting language tutorial:


I have no idea what tutorial you're talking about, but in C++, we normally represent text strings with std::string.

As it stands, your 'instruction' objects cannot safely be copied, because trying to copy them will just copy the '_data' pointer, and not the pointed-at data. When both the copy and original object die, they will both try to delete[] the same data. That's not allowed.

Not being able to copy the objects is bad. When you put things into a container, the container will copy the objects behind the scenes. In a few different situations, including the initial insertion into the container. After all, it can't very well just steal your local variable away from you, hmm?

Solution: use std::string to represent text strings, the way we normally do in C++.

Also, don't artificially pause your program at the end, please. Learn to run it properly, instead.


#include <iostream>
#include <string>
#include <vector>
#include <cassert> // it is not called assert.h any more.

enum opcode{op_talk, op_end, op_print};

class instruction
{
public:
instruction(opcode code) : _code(code), _data() {}
instruction(opcode code, const std::string& data, size_t data_size) : _code(code), _data(data) {}
opcode code() const { return _code; }
const std::string& data() const { return _data; }

private:
opcode _code;
std::string _data;
};


Share this post


Link to post
Share on other sites
Ok i have modified the code to the following(sorry I can't seem to figure out how to do a code block like Zahlman did, helo with that would be good):


#include <iostream>
#include <conio.h>
#include <vector>
#include <cassert>
#include <string>

enum opcode{op_talk, op_end, op_print};

class instruction
{
public:
instruction(opcode code) : _code(code), _data(0) {}
instruction(const instruction& copy_instruction)
{
_code = copy_instruction._code;
_data = copy_instruction._data;
}
instruction(opcode code, const std::string& data) : _code(code), _data(data){}
~instruction() {}
opcode code() const { return _code; }
const std::string data() const { return _data; }

private:
opcode _code;
std::string _data;
};

class script
{
public:
script(const std::vector<instruction> &instruction_list) : _instruction_list(instruction_list){}
const instruction* instruction_pointer() const { return &_instruction_list[0]; }
private:
std::vector<instruction> _instruction_list;
};

class virtual_machine
{
public:
virtual_machine() : _script_pointer(0), _instruction_pointer(0), _instruction(0), _script_count(0) {}

// a very basic interface
inline void execute(size_t script_id);
size_t load(const script& script) { return add_script(script); }

private: // useful abstractions
typedef const script* script_reference;
typedef const instruction* instruction_reference;
// pointers used as non-modifying dynamic references
private: // utilities
size_t add_script(const script& script) // add script to list and retrieve id
{
_script_list.push_back(script);
return _script_count++;
}
void select_script(size_t index) // set current script by id
{
assert(index < _script_count); // make sure the id is valid
_script_pointer = &_script_list[index];
_instruction_pointer = _script_pointer->instruction_pointer();
}

private: // data members
std::vector<script> _script_list;
script_reference _script_pointer; // current script
instruction_reference _instruction_pointer; // root instruction
instruction_reference _instruction; // current instruction
size_t _script_count; // track the loaded scripts
};

void virtual_machine::execute(size_t script_id)
{
select_script(script_id); // select our _instrPtr by script ID
_instruction = _instruction_pointer; // set our iterator to the beginning
while (_instruction)
{
switch(_instruction->code())
{
case op_talk:
std::cout << "I am talking." << std::endl;
++_instruction; // iterate
break;

case op_print:
//std::cout << _instruction->data() << std::endl;
++_instruction; // iterate
break;

case op_end:
_instruction = 0; // discontinue the loop
break;
}
}
}

void main()
{
virtual_machine vm;

std::string buffer = "this is printed data";

// build the script
std::vector<instruction> instruction_list;
instruction_list.push_back(instruction(op_talk)); // talk twice
instruction_list.push_back(instruction(op_print, buffer));
instruction_list.push_back(instruction(op_talk)); // talk twice
instruction_list.push_back(instruction(op_end)); // then end
//script script(instruction_list);

// load the script and save the id
//size_t script_id = vm.load(script);

// execute the script by its id
//vm.execute(script_id);
_getch();
}




and still getting the same access violation. I am quite confused about this issue as a few people on IRC have said it should work.

also the tutorial series i am talking about is this one(the first of 5 i think) http://www.gamedev.net/reference/articles/article1633.asp. I just wanted to following the tutorial till the end and then start modify things.

[Edited by - 3dmodelerguy on May 5, 2008 10:35:03 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy
Ok i have modified the code to the following(sorry I can't seem to figure out how to do a code block like Zahlman did, helo with that would be good)


Reading the FAQ could help. Use [ source ][ /source ]

About your problem, on which line are you getting an access violation ?

Share this post


Link to post
Share on other sites
Quote:

sorry I can't seem to figure out how to do a code block like Zahlman did, helo with that would be good


Just put your code inside [ source ][ /source ] tags (without the spaces).

Share this post


Link to post
Share on other sites
Here :

instruction(opcode code) : _code(code), _data(0) {}


"_data(0)" is calling this constructor :

basic_string(
const value_type* _Ptr,
const allocator_type& _Al = Allocator ( )
);


That's why you're getting an access violation, this constructor expects a C-string. Use _data(""), or don't call the constructor at all :

instruction(opcode code) : _code(code) {} // should work



Anyway, there might be other problems in your code if you have just text-replaced char* by std::string... Think before/while you're writing, not after

Share this post


Link to post
Share on other sites
Quote:
Original post by 3dmodelerguy
yea the _data was the issue. funny enough std::string works were char* as in the tutorial does not for some reason.

char* are evil

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this