- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
一般来说,我是 shared_ptr 和智能指针的新手。我的想法是智能指针通常不会泄漏内存。我正在编写一个巨大的链表文件,我将所有“原始”指针转换为智能指针后发生了一些内存泄漏。我正在使用带有“任意节点”的链表,其中每个节点都有一个 next
指针,以及 arb
指针,它指向同一链表中的任意节点。这可能会创建循环指针。问题是,在存在循环指针的情况下如何消除内存泄漏?
链表.hpp
:
#pragma once
#include <exception>
#include <iostream>
#include <unordered_map>
template <typename T> class LinkedList;
class Int;
template <typename T>
std::ostream& operator<<(std::ostream& os, const LinkedList<T>& list);
std::ostream& operator<<(std::ostream& os, const Int& num);
/** Node class
*
* @tparam T template type
*/
template <typename T>
class Node {
public:
/** Constructor */
Node(T e = T(0)) : _elem(e), _next(nullptr), _arb(nullptr) {}
// ~Node() { delete _next; }
public:
// Getters/Setters:
/** Return the value in the node
*
* @returns T value
*/
const T& value() const { return this->_elem; }
/** Return the next node
*
* @returns std::shared_ptr< Node<T> >
*/
std::shared_ptr<Node<T>> next() const { return this->_next; }
/** Return the arbitrary node
*
* @returns std::shared_ptr< Node<T> >
*/
std::shared_ptr<Node<T>> arb() const { return this->_arb; }
/** Set the value in the node
*
* @param T value
*/
void setValue(const T& e) { this->_elem = e; }
/** Set the next pointer
*
* @param std::shared_ptr< Node<T> > the next "next" pointer
*/
void setNext(std::shared_ptr< Node<T> > n) { this->_next = n; }
/** Set the arbitrary pointer
*
* @param std::shared_ptr< Node<T> > the next "arb" pointer
*/
void setArb(std::shared_ptr< Node<T> > n) { this->_arb = n; }
private:
T _elem; //!< Stored value
// std::shared_ptr< Node<T> > _next; //!< Next element
// std::shared_ptr< Node<T> > _arb; //!< Arbitrary element
std::shared_ptr< Node<T> > _next; //!< Next element
std::shared_ptr< Node<T> > _arb; //!< Arbitrary element
friend class LinkedList<T>; //!< Friend class
};
/** Singly Linked List
*
* @tparam T template type
*/
template <typename T>
class LinkedList {
public:
LinkedList();
// ~LinkedList();
public:
bool empty() const;
const T& front() const throw(std::range_error);
void addFront(const T& e);
void removeFront();
public:
// Housekeeping
std::size_t size() const;
std::shared_ptr< Node<T> > head();
void setHead(std::shared_ptr< Node<T> > h); // This is dangerous!!!
// template <typename U>
// friend std::ostream& operator<<(std::ostream& os, const LinkedList<U>& list);
std::shared_ptr< Node<T> > operator[](std::size_t idx);
friend std::ostream& operator<<<>(std::ostream& os, const LinkedList& list);
void printArb();
private:
std::shared_ptr< Node<T> > _head;
// std::size_t _size;
// Rust solutions after this point
public:
void reverse();
void reverseRecursive();
void deleteKey (T key);
LinkedList<T> deepCopy();
void sort();
private:
std::shared_ptr< Node<T> > _reverse_recursive(std::shared_ptr< Node<T> > node);
std::shared_ptr< Node<T> > _deep_copy_1 (std::shared_ptr< Node<T> > head);
std::shared_ptr< Node<T> > _deep_copy_2 (std::shared_ptr< Node<T> > head);
std::shared_ptr< Node<T> > _sorted_insert(std::shared_ptr< Node<T> > head, std::shared_ptr< Node<T> > node);
std::shared_ptr< Node<T> > _insertion_sort(std::shared_ptr< Node<T> > head);
};
/** Constructor */
template <typename T>
LinkedList<T>::LinkedList() : _head(nullptr)/*, _size(0)*/ {}
/** Destructor */
// template <typename T>
// LinkedList<T>::~LinkedList() {
// while (!empty()) removeFront();
// // delete _head;
// }
/** Empty?
*
* @returns bool True if empty
*/
template <typename T>
bool LinkedList<T>::empty() const {
return _head == nullptr;
}
/** Get front element (read-only)
*
* @returns T
*/
template <typename T>
const T& LinkedList<T>::front() const
throw (std::range_error) {
if (empty()) {
throw std::range_error("Linked List empty! Cannot get front()");
// return 0;
}
return _head->_elem;
}
/** Add element in the front of the list
*
* @param e Element to be added
*/
template <typename T>
void LinkedList<T>::addFront(const T& e) {
// std::shared_ptr< Node<T> > v = std::make_shared< Node<T> >();// (new Node<T>);
std::shared_ptr< Node<T> > v(new Node<T>);
v->_elem = e;
v->_next = _head;
_head = v;
// _size++;
}
/** Remove the first element
*
*/
template <typename T>
void LinkedList<T>::removeFront() {
if (this->empty()) return;
std::shared_ptr< Node<T> > old = _head;
_head = old->_next;
// _size--;
// delete old;
old.reset();
}
/** Number of elements in the list
*
* @returns std::size_t Number of elements in the list
*/
template <typename T>
std::size_t LinkedList<T>::size() const {
// return this->_size;
Node<T> head = this->head();
std::size_t len = 0;
while (head != nullptr) {
head = head->next();
len++;
}
return len;
}
/** Returns the head of the linked list
*
* @returns std::shared_ptr< Node<T> > the head of the current linked list
*/
template <typename T>
std::shared_ptr< Node<T> > LinkedList<T>::head() { return this->_head; }
/** Set the head to different node
*
* NOTE: this method is dangerous as it will lose information
* about other nodes!!!
*
* @params std::shared_ptr< Node<T> > the node to be set as head
*/
template <typename T>
void LinkedList<T>::setHead(std::shared_ptr< Node<T> > h) {
this->_head = h;
// this->resetSize();
}
/** Operator<< for the linked list
*
* @returns std::ostream
* @param LHS->std::ostream
* @param RHS->LinkedList<T>
*/
template <typename T>
std::ostream& operator<<(std::ostream& os, const LinkedList<T>& list) {
os << "HEAD->";
std::shared_ptr< Node<T> > ptr = list._head;
while (ptr != nullptr) {
os << ptr->_elem << "->";
ptr = ptr->_next;
}
os << "NULL";
// delete ptr;
ptr.reset();
return os;
/*
os << "[HEAD]\n V\n";
std::shared_ptr< Node<T> > ptr = list._head;
while (ptr != nullptr) {
os << "[" << ptr->_elem << "]->";
os << "[";// << ( (ptr->arb() == nullptr) ? "NULL" : ptr->arb()->_elem) << "]\n V";
if (ptr->arb() == nullptr)
os << "NULL";
else
os << ptr->arb()->_elem << "|" << (ptr->arb());
os << "]\n V\n";
ptr = ptr->_next;
}
os << "[NULL]";
delete ptr;
return os;
*/
}
template <typename T>
void LinkedList<T>::printArb() {
std::cout << "[HEAD]\n V\n";
std::shared_ptr< Node<T> > ptr = this->_head;
while (ptr != nullptr) {
std::cout << "[" << ptr->_elem << "]->";
std::cout << "[";// << ( (ptr->arb() == nullptr) ? "NULL" : ptr->arb()->_elem) << "]\n V";
if (ptr->arb() == nullptr)
std::cout << "NULL";
else
std::cout << ptr->arb()->_elem << "|" << (ptr->arb());
std::cout << "]\n V\n";
ptr = ptr->_next;
}
std::cout << "[NULL]";
// delete ptr;
ptr.reset();
// return std::cout;
}
/* Rust solutions after this point */
/** Reverse the linked list using solution 1 (iterative)
*/
template <typename T>
void LinkedList<T>::reverse() {
if (this->_head == nullptr || this->_head->_next == nullptr)
return;
std::shared_ptr< Node<T> > list_to_do = this->_head->_next;
this->_head->_next = nullptr;
while (list_to_do != nullptr) {
std::shared_ptr< Node<T> > temp = list_to_do;
list_to_do = list_to_do->_next;
temp->_next = _head;
_head = temp;
}
// delete list_to_do;
list_to_do.reset();
}
/** Reverse the linked list using solution 2 (recursive)
*/
template <typename T>
void LinkedList<T>::reverseRecursive() {
this->_head = this->_reverse_recursive(this->_head); // This method is declared later in the "Helpers" section
}
/** Delete a node with key `key` from the linked list
*
* @params T Key value
*/
template <typename T>
void LinkedList<T>::deleteKey (T key) {
std::shared_ptr< Node<T> > prev = nullptr;
std::shared_ptr< Node<T> > current = this->head();
while (current != nullptr) {
if (current->value() == key) {
// this->_size--;
break; // Found it! :)
}
prev = current;
current = current->next();
}
if (current == nullptr) {
return; // Didn't find it :(
}
if (current == this->head()) {
this->setHead(this->head()->next());
} else {
prev->setNext(current->next());
}
// delete current;
current.reset();
}
/** Deep copy method
*
* @returns LinkedList<T> New linked list
*/
template <typename T>
LinkedList<T> LinkedList<T>::deepCopy() {
LinkedList<T> copy;
copy.setHead(this->_deep_copy_2(this->head()));
return copy;
}
/** Sort the current linked list */
template <typename T>
void LinkedList<T>::sort() {
this->setHead(this->_insertion_sort(this->head()));
}
//////////////////////////////////////
// Helpers:
/** Reverse a singly linked list (Recursive)
*
* @returns std::shared_ptr< Node<T> > The head of the reversed linked list
* @param std::shared_ptr< Node<T> > The head of the linked list to be reversed
*/
template <typename T>
std::shared_ptr< Node<T> > LinkedList<T>::_reverse_recursive (std::shared_ptr< Node<T> > node) {
// If the size of the linked list = 0 or 1, nothing to do :)
if (node == nullptr || node->next() == nullptr)
return node;
std::shared_ptr< Node<T> > reversed_list = this->_reverse_recursive(node->next());
node->next()->setNext(node);
node->setNext(nullptr);
return reversed_list;
}
/** Deep copy the single linked list (solution 1)
*
* @returns std::shared_ptr< Node<T> > The head of the new linked list
* @params std::shared_ptr< Node<T> > The head of the original linked list
*/
template <typename T>
std::shared_ptr< Node<T> > LinkedList<T>::_deep_copy_1 (std::shared_ptr< Node<T> > head) {
// If the linked list is empty, return
if (head == nullptr) {
return nullptr;
}
std::shared_ptr< Node<T> > current = head;
std::shared_ptr< Node<T> > new_head = nullptr;
std::shared_ptr< Node<T> > new_prev = nullptr;
std::unordered_map<std::shared_ptr< Node<T> >, std::shared_ptr< Node<T> >> map;
// Create copy of the linked list, recording the corresponding
// nodes in hashmap without updating arbitrary pointer
while (current != nullptr) {
std::shared_ptr< Node<T> > new_node = std::make_shared< Node<T> >(current->value());
// new Node<T>(current->value());
// Copy the old arbitrary pointer in the new node
new_node->setArb(current->arb());
if (new_prev != nullptr) {
new_prev->setNext(new_node);
} else {
new_head = new_node;
}
map[current] = new_node;
new_prev = new_node;
current = current->next();
}
std::shared_ptr< Node<T> > new_current = new_head;
// Update arbitrary pointer:
while (new_current != nullptr) {
if (new_current->arb() != nullptr) {
std::shared_ptr< Node<T> > node = map[new_current->arb()];
new_current->setArb(node);
}
new_current = new_current->next();
}
return new_head;
}
/** Deep copy the single linked list (solution 2)
*
* @returns std::shared_ptr< Node<T> > The head of the new linked list
* @params std::shared_ptr< Node<T> > The head of the original linked list
*/
template <typename T>
std::shared_ptr< Node<T> > LinkedList<T>::_deep_copy_2 (std::shared_ptr< Node<T> > head) {
// If the linked list is empty, return
if (head == nullptr) {
return nullptr;
}
std::shared_ptr< Node<T> > current(head);
// Inserting new nodes within the existing linked list
while (current != nullptr) {
// std::shared_ptr< Node<T> > new_node(std::make_shared< Node<T> >(current->value()));
std::shared_ptr< Node<T> > new_node(new Node<T>(current->value()));
new_node->setNext(current->next());
current->setNext(new_node);
current = new_node->next();
}
// Setting correct arbitrary pointers
current = head;
while (current != nullptr) {
if (current->arb() != nullptr) {
current->next()->setArb(current->arb()->next());
}
current = current->next()->next();
}
// Separating lists
current = head;
std::shared_ptr< Node<T> > new_head(head->next());
std::shared_ptr< Node<T> > copied_current(nullptr);
while (current != nullptr) {
copied_current = current->next();
current->setNext(copied_current->next());
if (copied_current->next() != nullptr) {
copied_current->setNext(copied_current->next()->next());
}
current = current->next();
}
return new_head;
}
/** Insert in a sorted manner
*
* This method looks for an appropriate position
* for a given node and inserts it into the linked
* list with head "head"
*
* @returns std::shared_ptr< Node<T> > The head of the new linked list
* @param std::shared_ptr< Node<T> > head -> the head of the linked list
* @param std::shared_ptr< Node<T> > node -> node to be inserted
*/
template <typename T>
std::shared_ptr< Node<T> > LinkedList<T>::_sorted_insert(std::shared_ptr< Node<T> > head, std::shared_ptr< Node<T> > node) {
if (node == nullptr) {
return head;
}
if (head == nullptr || node->value() <= head->value()) {
node->setNext(head);
return node;
}
std::shared_ptr< Node<T> > curr = head;
while (curr->next() != nullptr && curr->next()->value() < node->value()) {
curr = curr->next();
}
node->setNext(curr->next());
curr->setNext(node);
return head;
}
/** Sort the linked list (destructive)
*
* Sort the linked list and destroy the original
*
* @returns std::shared_ptr< Node<T> > The head of the new linked list
* @param std::shared_ptr< Node<T> > head -> the head of the old linked list
*/
template <typename T>
std::shared_ptr< Node<T> > LinkedList<T>::_insertion_sort(std::shared_ptr< Node<T> > head){
std::shared_ptr< Node<T> > sorted = nullptr;
std::shared_ptr< Node<T> > curr = head;
while (curr != nullptr) {
std::shared_ptr< Node<T> > temp = curr->next();
sorted = this->_sorted_insert(sorted, curr);
curr = temp;
}
return sorted;
}
//////////////////////////////////////
// This is a specialized Linked List
// used for integer representation
/** Int class
*
* Every digit in the integer is represented as a node in
* a singly linked list starting from ones
*/
class Int {
public:
Int() { this->_num.setHead(nullptr); }
Int(int n);
Int (std::shared_ptr< Node<int> > n) { this->_num.setHead(n); }
// ~Int();
public:
std::shared_ptr< Node<int> > getHead() const {
return const_cast<Int*>(this)->_num.head(); }
Int& operator=(const Int& rhs);
int value() const;
// Int operator+(const Int& a, const Int& b);
public:
friend std::ostream& operator<<(std::ostream& os, const Int& num);
friend Int operator+(const Int&, const Int&);
private:
LinkedList<int> _num;
// bool negative;
};
/** Signed constructor
*/
Int::Int(int n) {
// delete &_num;
this->_num = LinkedList<int>();
if (n < 0)
throw (std::range_error("No support for negative numbers...!"));
do {
_num.addFront(n % 10);
n = n / 10;
} while (n > 0);
_num.reverse();
}
/*
Int::~Int() {
while (!this->_num.empty()) this->_num.removeFront();
}
*/
/** Copy assignment !!!
*/
Int& Int::operator=(const Int& rhs) {
while (!this->_num.empty()) this->_num.removeFront();
int n = rhs.value();
if (n < 0)
throw (std::range_error("No support for negative numbers...!"));
do {
this->_num.addFront(n % 10);
n = n / 10;
} while (n > 0);
this->_num.reverse();
return *this;
}
/** Return the value
*/
int Int::value() const {
long exp = 1;
int n = 0;
std::shared_ptr< Node<int> > ptr = this->getHead();
while (ptr != nullptr) {
n += exp * ptr->value();
exp *= 10;
ptr = ptr->next();
}
// delete ptr;
return n;
}
/** Addition operator overloading
*/
Int operator+(const Int& A, const Int& B) {
std::shared_ptr< Node<int> > a = A.getHead();
std::shared_ptr< Node<int> > b = B.getHead();
std::shared_ptr< Node<int> > result = nullptr;
std::shared_ptr< Node<int> > last = nullptr;
int carry = 0;
while (a != nullptr || b != nullptr || carry > 0) {
int first = (a == nullptr ? 0 : a->value());
int second = (b == nullptr ? 0 : b->value());
int sum = first + second + carry;
// cout << "DEBUG: " << first << ' ' << second << endl;
std::shared_ptr< Node<int> > pNew = std::make_shared< Node<int> >(sum%10);
// (new Node<int>(sum % 10));
carry = sum / 10;
if (result == nullptr) {
result = pNew;
} else {
last->setNext(pNew);
}
last = pNew;
if (a != nullptr) {
a = a->next();
}
if (b != nullptr) {
b = b->next();
}
}
// This is the head of the new LinkedList:
// return result;
Int temp;
temp._num.setHead(result);
return temp;
}
/** Ostream method
*/
std::ostream& operator<<(std::ostream& os, const Int& num) {
/*Node<int> *ptr = num.getHead();
int counter = 1;
int number = 0;
while (ptr != nullptr) {
number = counter * ptr->value();
ptr = ptr->next();
counter *= 10;
}
os << number;
return os;*/
os << num.value();
return os;
}
测试.cpp
:
#include <iostream>
#include <exception>
#include "LinkedList.hpp"
using namespace std;
int main() {
LinkedList<int> list;
cout << list << endl;
try {
cout << list.front() << endl;
} catch (std::exception& e) {
cout << "Exception caught: " << e.what() << endl;
}
list.addFront('a'); // Should be invalid, but works
list.addFront(21);
list.addFront(14);
list.addFront(7);
cout << "Initial list:\n";
cout << list << endl;
// Check iterative reversing:
cout << "\nAfter iterative reverse:\n";
list.reverse();
cout << list << endl;
// Check recursive reversing:
cout << "\nAfter recursive reverse:\n";
list.reverseRecursive();
cout << list << endl;
// Check deleting nodes:
cout << "\nAfter deleting non-existing key:\n";
list.deleteKey(0);
cout << list << endl;
cout << "\nAfter deleting head key:\n";
list.deleteKey(list.head()->value());
cout << list << endl;
cout << "\nAfter deleting middle key:\n";
list.deleteKey(list.head()->next()->value());
cout << list << endl;
cout << "\nAfter deleting key:\n";
list.deleteKey(list.head()->next()->value());
cout << list << endl;
cout << "\nCreate an Linked List Int:\n";
Int num(100);
cout << num << endl;
num = Int(200);
cout << num << endl;
Int a(123);
Int b(897);
Int c = a + b;
cout << c << endl;
LinkedList<int> listArb;
listArb.addFront(21);
listArb.addFront(14);
listArb.addFront(7);
listArb.head()->setArb(listArb.head()->next()->next());
listArb.head()->next()->next()->setArb(listArb.head());
cout << listArb << endl;
LinkedList<int> listArbCopy = listArb.deepCopy();
// listArbCopy.setHead(deep_copy_arbitrary_pointer(listArb.head()));
// Change some stuff to check if the linked lists are really separate
listArbCopy.head()->next()->setValue(123);
listArb.head()->setValue(321);
cout << listArbCopy << endl;
cout << listArb << endl;
// Check the sorting algos:
LinkedList<int> sort;
sort.addFront(11);
sort.addFront(82);
sort.addFront(23);
sort.addFront(29);
cout << sort << endl;
sort.sort();
cout << sort << endl;
return 0;
}
最佳答案
只需将 _arb 更改为
std::weak_ptr< T > _arb;
因为所有节点都属于 shared_ptr,所以 weak_ptr 仅指没有任何所有权的任意节点。要使用 weak_ptr,您会在打算使用它时获得它的 shared_ptr:
std::shared_ptr< T > sp( this->_arb );
return sp;
以上是您如何更改 Node 类中的“arb”函数。
注意:如果出于某种原因(这对 weak_ptr 是普遍的)_arb 一旦指向列表中其他地方的有效 shared_ptr,然后随后该节点被删除,上述函数将返回一个空的 shared_ptr 作为 weak_ptr 消失的指示.
关于C++:shared_ptr 泄漏,链表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32674556/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!