我正在使用C ++和Allegro开发一款简单的游戏。我遇到Access violation
运行时错误,其中vector
structs
unique_ptrs
包含ALLEGRO_BITMAPs
到struct Skin {
std::unique_ptr<ALLEGRO_BITMAP> img;
Skin();
Skin(ALLEGRO_BITMAP*);
Skin& operator=(const Skin& s);
Skin(const Skin& s);
};
。
这是我的结构声明。
Skin::Skin() {
img.reset();
}
Skin::Skin(ALLEGRO_BITMAP* bitmap) {
img.reset(bitmap);
}
Skin::Skin(const Skin& s) {
img.reset(s.img.get());
}
Skin& Skin::operator=(const Skin& s) {
img.reset(s.img.get());
return *this;
}
以下是另一个文件中构造函数的定义。
generateBase(world, display.get());
以下是在我的访问冲突之前调用的代码。
void generateBase(World& world, ALLEGRO_DISPLAY* display) {
int x = TILESIZE - WIDTH;
int y = HEIGHT - TILESIZE;
int groundWidth = 3 * WIDTH - 2 * TILESIZE;
Point min{ x, y };
Point max{ x + groundWidth, y + (int)TILESIZE };
ALLEGRO_BITMAP* black = al_create_bitmap(groundWidth, TILESIZE);
ALLEGRO_BITMAP* white = al_create_bitmap(groundWidth, TILESIZE);
al_set_target_bitmap(black);
al_clear_to_color(al_map_rgb(0, 0, 0));
al_set_target_bitmap(white);
al_clear_to_color(al_map_rgb(255, 255, 255));
al_set_target_bitmap(al_get_backbuffer(display));
std::cout << "Errors incoming!" << endl;
createPlayer(world, x, y, 0, 0, 5, vector < AABB > { AABB(min, max) }, vector < Skin > { Skin(black), Skin(white) });
std::cout << "Did we make it?" << endl;
}
调用此功能。
unsigned int createPlayer(World& world, int x, int y, float dx, float dy, float speed, vector<AABB>& mesh, vector<Skin>& imgs) {
unsigned int entity = newEntityIndex(world);
world.masks[entity].set(COMPONENT_TYPE);
world.masks[entity].set(COMPONENT_POINT);
world.masks[entity].set(COMPONENT_UNITVECTOR);
world.masks[entity].set(COMPONENT_SPEED);
world.masks[entity].set(COMPONENT_COLLISIONMESH);
world.masks[entity].set(COMPONENT_SKINLIST);
world.types[entity] = TYPE_PLAYER;
world.points[entity] = Point(x, y);
world.unitVectors[entity] = UnitVector(dx, dy);
world.speeds[entity] = Speed(speed);
world.collisionMeshes[entity].mesh = mesh;
cout << "Starting vector copy" << endl;
for (auto skin : imgs) {
world.skinLists[entity].imgs.push_back(move(skin));
}
cout << "Ending vector copy" << endl;
return entity;
}
反过来调用此功能。
namespace std {
template<>
class default_delete < ALLEGRO_BITMAP > {
public:
void operator()(ALLEGRO_BITMAP* ptr) {
cout << ptr << endl;
al_destroy_bitmap(ptr);
}
};
}
这是我对unique_ptr的删除。
Errors incoming!
Starting vector copy
00AF9468
00AF9468
这是输出。
createPlayer
当我通过删除generateBase
修改Skin(white)
中的Errors incoming!
Starting vector copy
00799468
Ending vector copy
00799468
来电时,输出更改为。
vector
输出的变化让我感到有些困惑,但我最大的问题是我需要改变一些关于如何复制structs
unique_ptrs
package com.pluralsight.model;
import hello.User;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.validator.constraints.Range;
import org.springframework.web.bind.annotation.ModelAttribute;
@Entity
@Table(name="goals")
public class Goal {
public static final String FIND_ALL_GOALS = "findALLGoals";
public static final String FIND_GOAL_REPORTS = "findGoalReports";
@Id
@GeneratedValue
@Column(name="GOAL_ID")
private Long id;
@Range(min = 1, max = 120)
@Column(name="MINUTES")
private int minutes;
// @OneToMany(mappedBy="goal",cascade=CascadeType.ALL, fetch=FetchType.LAZY)
// private List<Exercise> exercises = new ArrayList<Exercise>();
@ManyToOne
@JoinColumn(name="USER_NAME")
private User user;
//
// public List<Exercise> getExercises() {
// return exercises;
// }
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Long getId() {
return id;
}
public int getMinutes() {
return minutes;
}
// public void setExercises(List<Exercise> exercises) {
// this.exercises = exercises;
// }
public void setId(Long id) {
this.id = id;
}
public void setMinutes(int minutes) {
this.minutes = minutes;
}
}
package com.pluralsight.controller;
import java.util.List;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import com.pluralsight.model.Goal;
import com.pluralsight.model.GoalReport;
import com.pluralsight.model.User;
import com.pluralsight.service.GoalService;
@Controller
@SessionAttributes("goal")
public class GoalController {
@Autowired
private GoalService goalService;
@RequestMapping(value = "addGoal", method = RequestMethod.GET)
public String addGoal(Model model, HttpSession session ) {
//Goal goal = new Goal();
Goal goal = (Goal)session.getAttribute("goal");
if(goal == null){
goal = new Goal();
goal.setMinutes(10);
}
model.addAttribute("goal", goal);
return "addGoal";
}
@RequestMapping(value = "addGoal", method = RequestMethod.POST)
public String updateGoal(@Valid @ModelAttribute Goal goal, BindingResult result) {
System.out.println("result has errors: " + result.hasErrors());
System.out.println("Goal set: " + goal.getMinutes());
if(result.hasErrors()) {
return "addGoal";
}else{
goalService.save(goal);
}
return "redirect:index.jsp";
}
@RequestMapping(value="getGoals", method= RequestMethod.GET)
public String getGoals(Model model){
List<Goal> goals = goalService.findAllGoals();
model.addAttribute("goals", goals);
return "getGoals";
}
@RequestMapping(value="getGoalReports", method= RequestMethod.GET)
public String getGoalReports(Model model){
List<GoalReport> goalReports = goalService.findAllGoalReports();
model.addAttribute("goalReports", goalReports);
return "getGoalReports";
}
}
的问题,以便我不要不要尝试两次删除相同的指针。
提前致谢!
答案 0 :(得分:3)
首先要理解的是,您只能有一个包含指向特定对象的指针的std::unique_ptr
对象。您的Skin(const Skin& s)
构造函数违反了此原则,导致unique_ptr
的两个副本。如果您的对象包含unique_ptr
个成员,则需要执行以下操作之一:
al_clone_bitmap
来复制资源。其次,当您在unique_ptr
中持有资源时,您希望在创建资源的同一位置初始化unique_ptr
。例如,不要创建局部变量ALLEGRO_BITMAP* black
,而是使用以下内容:
std::unique_ptr<ALLEGRO_BITMAP> black(al_create_bitmap(groundWidth, TILESIZE));
由于此代码直接从unique_ptr
的结果创建al_create_bitmap
,因此您需要删除 Skin
构造函数,其中包含ALLEGRO_BITMAP*
1}}并将其替换为:
Skin::Skin(std::unique_ptr<ALLEGRO_BITMAP>&& bitmap)
: img(bitmap)
{
}
然后,您可以将Skin
移入其中来创建unique_ptr
:
Skin(std::move(black))
将上述内容放在一起,工作副本构造函数可能如下所示。它不是特别有效,但它是安全的。
Skin::Skin(const Skin& s)
: img(al_clone_bitmap(s.img.get()))
{
}
答案 1 :(得分:1)
问题在于:
Skin::Skin(const Skin& s) {
img.reset(s.img.get());
}
Skin& Skin::operator=(const Skin& s) {
img.reset(s.img.get());
您正在从一个unique_ptr窃取原始指针并将其分配给另一个。现在unique_ptr属于RAII类别。只要它们还活着,它们就希望拥有物体的寿命。 当你这样做时
img.reset(s.img.get());
你从一个unique_ptr中取出指针并移交给另一个unique_ptr。现在,unique_ptr1认为它拥有底层对象而不知道还有另一个相同的unique_ptr2。因此,当他们死亡时,他们将愉快地释放为_Ptr分配的内存。因此,您的代码必然会最终访问/释放已经被第一个unique_ptr消失的内存。
您必须移动unique_ptr(从而产生所有权)或在s.img上显式调用release