Access Violation?

Started by
8 comments, last by rolkA 15 years, 11 months ago
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]
Advertisement
Probably because your instruction class doesn't obey the rule of three. In particular, you're lacking a valid copy constructor and assignment operator.
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;};
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]
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 ?
English is not my native language.Sam.
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).
thanks, I have updated my posts.
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
English is not my native language.Sam.
yea the _data was the issue. funny enough std::string works were char* as in the tutorial does not for some reason.
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
English is not my native language.Sam.

This topic is closed to new replies.

Advertisement