diff --git a/aegisub/src/ass_attachment.h b/aegisub/src/ass_attachment.h
index 54b1e5111ce536b592cc2257c6a63bf60e34b4b4..7c0aafffcdd2ee74fe809ccd06d6a34860e36b0f 100644
--- a/aegisub/src/ass_attachment.h
+++ b/aegisub/src/ass_attachment.h
@@ -22,7 +22,7 @@
 #include <vector>
 
 /// @class AssAttachment
-class AssAttachment : public AssEntry, public AssEntryListHook {
+class AssAttachment : public AssEntry {
 	/// ASS uuencoded entry data, including header.
 	boost::flyweight<std::string> entry_data;
 
diff --git a/aegisub/src/ass_file.cpp b/aegisub/src/ass_file.cpp
index 8375bcf1b2ced48d9c1a3b61e77255194fc41dfa..b90117c59c76c3e637876772b46b9db34f0530f1 100644
--- a/aegisub/src/ass_file.cpp
+++ b/aegisub/src/ass_file.cpp
@@ -34,7 +34,6 @@ AssFile::AssFile() { }
 AssFile::~AssFile() {
 	Styles.clear_and_dispose([](AssStyle *e) { delete e; });
 	Events.clear_and_dispose([](AssDialogue *e) { delete e; });
-	Attachments.clear_and_dispose([](AssAttachment *e) { delete e; });
 }
 
 void AssFile::LoadDefault(bool include_dialogue_line) {
@@ -56,6 +55,7 @@ void AssFile::LoadDefault(bool include_dialogue_line) {
 
 AssFile::AssFile(const AssFile &from)
 : Info(from.Info)
+, Attachments(from.Attachments)
 {
 	Styles.clone_from(from.Styles,
 		[](AssStyle const& e) { return new AssStyle(e); },
@@ -63,9 +63,6 @@ AssFile::AssFile(const AssFile &from)
 	Events.clone_from(from.Events,
 		[](AssDialogue const& e) { return new AssDialogue(e); },
 		[](AssDialogue *e) { delete e; });
-	Attachments.clone_from(from.Attachments,
-		[](AssAttachment const & e) { return new AssAttachment(e); },
-		[](AssAttachment *e) { delete e; });
 }
 
 void AssFile::swap(AssFile& from) throw() {
@@ -87,7 +84,7 @@ void AssFile::InsertAttachment(agi::fs::path const& filename) {
 	if (ext == ".ttf" || ext == ".ttc" || ext == ".pfb")
 		group = AssEntryGroup::FONT;
 
-	Attachments.push_back(*new AssAttachment(filename, group));
+	Attachments.emplace_back(filename, group);
 }
 
 std::string AssFile::GetScriptInfo(std::string const& key) const {
diff --git a/aegisub/src/ass_file.h b/aegisub/src/ass_file.h
index d7a748e25c60acc2e3cd136fa2e23f8d13367b1a..b24a68238cb21a5e8015f13c345162ecc87a2d9a 100644
--- a/aegisub/src/ass_file.h
+++ b/aegisub/src/ass_file.h
@@ -65,7 +65,7 @@ public:
 	std::vector<AssInfo> Info;
 	EntryList<AssStyle> Styles;
 	EntryList<AssDialogue> Events;
-	EntryList<AssAttachment> Attachments;
+	std::vector<AssAttachment> Attachments;
 
 	AssFile();
 	AssFile(const AssFile &from);
diff --git a/aegisub/src/dialog_attachments.cpp b/aegisub/src/dialog_attachments.cpp
index 50434ed721d391f71ebb95b962e64061d59d6bc7..23e34b5f188db6039a633f63234fd9158006834e 100644
--- a/aegisub/src/dialog_attachments.cpp
+++ b/aegisub/src/dialog_attachments.cpp
@@ -102,7 +102,6 @@ void DialogAttachments::UpdateList() {
 		listView->InsertItem(row, to_wx(attach.GetFileName(true)));
 		listView->SetItem(row, 1, PrettySize(attach.GetSize()));
 		listView->SetItem(row, 2, to_wx(attach.GroupHeader()));
-		listView->SetItemPtrData(row, wxPtrToUInt(&attach));
 	}
 }
 
@@ -153,7 +152,7 @@ void DialogAttachments::OnExtract(wxCommandEvent &) {
 		path = SaveFileSelector(
 			_("Select the path to save the file to:"),
 			"Path/Fonts Collector Destination",
-			((AssAttachment*)wxUIntToPtr(listView->GetItemData(i)))->GetFileName(),
+			ass->Attachments[i].GetFileName(),
 			".ttf", "Font Files (*.ttf)|*.ttf",
 			this);
 		fullPath = true;
@@ -162,20 +161,16 @@ void DialogAttachments::OnExtract(wxCommandEvent &) {
 
 	// Loop through items in list
 	while (i != -1) {
-		AssAttachment *attach = (AssAttachment*)wxUIntToPtr(listView->GetItemData(i));
-		attach->Extract(fullPath ? path : path/attach->GetFileName());
+		auto& attach = ass->Attachments[i];
+		attach.Extract(fullPath ? path : path/attach.GetFileName());
 		i = listView->GetNextSelected(i);
 	}
 }
 
 void DialogAttachments::OnDelete(wxCommandEvent &) {
-	auto i = listView->GetFirstSelected();
-	if (i == -1) return;
-
-	while (i != -1) {
-		delete (AssEntry*)wxUIntToPtr(listView->GetItemData(i));
-		i = listView->GetNextSelected(i);
-	}
+	size_t removed = 0;
+	for (auto i = listView->GetFirstSelected(); i != -1; i = listView->GetNextSelected(i))
+		ass->Attachments.erase(ass->Attachments.begin() + i - removed++);
 
 	ass->Commit(_("remove attachment"), AssFile::COMMIT_ATTACHMENT);
 
diff --git a/aegisub/src/subs_controller.cpp b/aegisub/src/subs_controller.cpp
index a82846362147685a11666f2f5842b0d85f9ec47d..ddcdad29f305603817ef3c03a6375ec7c74409d6 100644
--- a/aegisub/src/subs_controller.cpp
+++ b/aegisub/src/subs_controller.cpp
@@ -54,20 +54,21 @@ namespace {
 }
 
 struct SubsController::UndoInfo {
+	wxString undo_description;
+	int commit_id;
+
 	std::vector<std::pair<std::string, std::string>> script_info;
 	std::vector<AssStyle> styles;
 	std::vector<AssDialogueBase> events;
-	std::vector<AssAttachment> graphics;
-	std::vector<AssAttachment> fonts;
+	std::vector<AssAttachment> attachments;
 
 	mutable std::vector<int> selection;
 	int active_line_id = 0;
 
-	wxString undo_description;
-	int commit_id;
-
 	UndoInfo(const agi::Context *c, wxString const& d, int commit_id)
-	: undo_description(d), commit_id(commit_id)
+	: undo_description(d)
+	, commit_id(commit_id)
+	, attachments(c->ass->Attachments)
 	{
 		script_info.reserve(c->ass->Info.size());
 		for (auto const& info : c->ass->Info)
@@ -79,20 +80,6 @@ struct SubsController::UndoInfo {
 		events.reserve(c->ass->Events.size());
 		events.assign(c->ass->Events.begin(), c->ass->Events.end());
 
-		for (auto const& line : c->ass->Attachments) {
-			switch (line.Group()) {
-			case AssEntryGroup::FONT:
-				fonts.push_back(line);
-				break;
-			case AssEntryGroup::GRAPHIC:
-				graphics.push_back(line);
-				break;
-			default:
-				assert(false);
-				break;
-			}
-		}
-
 		UpdateActiveLine(c);
 		UpdateSelection(c);
 	}
@@ -111,10 +98,7 @@ struct SubsController::UndoInfo {
 			c->ass->Info.push_back(*new AssInfo(info.first, info.second));
 		for (auto const& style : styles)
 			c->ass->Styles.push_back(*new AssStyle(style));
-		for (auto const& attachment : fonts)
-			c->ass->Attachments.push_back(*new AssAttachment(attachment));
-		for (auto const& attachment : graphics)
-			c->ass->Attachments.push_back(*new AssAttachment(attachment));
+		c->ass->Attachments = attachments;
 		for (auto const& event : events) {
 			auto copy = new AssDialogue(event);
 			c->ass->Events.push_back(*copy);