天道酬勤,学无止境

在考虑对齐要求时一般重载 operator new(Generically overloading operator new while considering alignment requirements)

问题

情况

我正在为动态内存(取消)分配编写内存管理器。 对于在调用operator new (或delete )时class A使用它, class A继承自class CustomAllocate就足够了,它本身以使用内存管理器的方式重载newdelete

问题

但是,显然我完全错过了对齐要求。 不幸的是, CustomAllocate::new没有关于继承自它的class A应该如何对齐的信息,因为唯一的参数是所请求内存的大小。 我正在寻找一种方法来包含对齐信息,而不必在每个class A中重载new (和delete )来使用内存管理器。

想法 1(以及为什么它不起作用)

使用表示对齐要求的整数值模板class CustomAllocate并像这样继承: class A : public CustomAllocate< alignof(A) >

不可能,因为alignof(A)在必须作为模板参数传递时不知道,即使传递的参数永远不应该改变class A的对齐要求。

想法 2(以及为什么它不起作用)

拥有一个纯虚函数virtual int CustomAllocate::getAlignment() = 0 ,通过复制粘贴类似return alignof(A);的方式在每个class A中实现。 .

不可能,因为new是静态的,因此永远无法访问虚函数。


有什么工作想法吗?

回答1

令我惊讶的是,以下似乎有效:

template <typename T> class CustomAllocate
{
public:
    void* operator new (std::size_t count)
    {
        std::cout << "Calling new, aligment = " << alignof (T) << "\n";
        return aligned_alloc (alignof (T), count);
    }

    void operator delete (void *p)
    {
        std::cout << "Calling delete\n";
        free (p);
    }
};

测试程序:

class A : public CustomAllocate <A>
{
public:
    A (int a, int b) : a (a), b (b) { }
    int a, b;
};

int main ()
{
    A *x = new A (1, 2);
    std::cout << x->a << ", " << x->b << "\n";
    delete x;
}

输出:

Calling new, aligment = 4
1, 2
Calling delete

现场演示

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 有什么理由使全局new和delete重载吗?(Any reason to overload global new and delete?)
    问题 除非您要对OS或嵌入式系统的各个部分进行编程,否则是否有理由这样做? 我可以想象,对于某些经常创建和销毁的特定类,这些类经常会导致内存管理功能超载或引入对象池,这可能会降低开销,但是在全局范围内执行这些操作? 添加我刚刚在重载的删除功能中发现了一个错误-内存并不总是被释放。 那是在不太重要的内存应用程序中。 同样,禁用这些过载只会使性能降低约0.5%。 回答1 由于许多原因,我们使我在其中工作的全局new和delete运算符超载: 集中所有小的分配-减少开销,减少碎片,可以提高大量分配小的应用程序的性能以已知的生命周期来进行分配框架-忽略所有释放,直到此期间结束,然后将所有释放一起释放(不可否认,我们对本地操作符的重载要比对全局的重载更多) 对齐调整-缓存线边界等分配填充-帮助公开未初始化变量的使用免费填充-帮助暴露以前删除的内存的使用情况延迟免费-增加免费填充的有效性,偶尔提高性能前哨或围栏-帮助揭示缓冲区溢出,溢出和偶尔出现的狂野指针重定向分配-考虑到NUMA,特殊的内存区域,甚至使单独的系统在内存中保持独立(例如,嵌入式脚本语言或DSL) 垃圾收集或清理-再次对那些嵌入式脚本语言有用堆验证-您可以每N次分配/释放一次遍历堆数据结构,以确保一切正常记帐,包括泄漏跟踪和使用情况快照/统计信息(堆栈,分配期限等) 新/删除记帐的想法实际上是灵活而强大的:例如
  • 运算符新的重载和对齐(operator new overloading and alignment)
    问题 我正在重载operator new ,但最近遇到对齐问题。 基本上,我有一个IBase类,它为所有必需的变体提供operator new和delete 。 所有类都从IBase派生,因此也使用自定义分配器。 我现在面临的问题是我有一个孩子Foo ,它必须对齐16个字节,而其他所有对齐到8个字节就可以了。 但是,我的内存分配器仅默认情况下对齐8字节边界,因此现在IBase::operator new的代码返回了一块不可用的内存。 应该如何正确解决呢? 我可以简单地将所有分配强制为16个字节,这将正常工作,直到弹出一个32字节的对齐类型为止。 弄清楚operator new内部的对齐方式似乎并不容易(我可以在其中进行虚拟函数调用以获得实际对齐方式吗?)推荐的处理方式是什么? 我知道malloc应该返回一块适合所有情况的内存,不幸的是,这个“一切”都不包括SSE类型,我真的很想让它工作,而无需用户记住哪种类型具有哪种类型。结盟。 回答1 这是一个可能的解决方案。 它将始终选择给定层次结构中具有最高对齐方式的运算符: #include <exception> #include <iostream> #include <cstdlib> // provides operators for any alignment >= 4 bytes template<int Alignment>
  • 为什么 + 运算符重载返回类型是类类型而不是整数?(Why does + operator overloading return type is class type not integer?)
    问题 这篇文章作者选择了返回类型为class type http://www.learncpp.com/cpp-tutorial/92-overloading-the-arithmetic-operators/强调文本,我们可以直接把返回类型改成return int ,因为我想做下面的事情,我试过这个,效果很好,作者为什么要设置返回类型类?? #include <cstdlib> #include <iostream> using namespace std; class Cents // defining new class { private: int m_Cents; int m_Cents2; public: Cents(int Cents=0, int Cents2=0) // default constructor { m_Cents=Cents; m_Cents2=Cents2; } Cents(const Cents &c1) {m_Cents = c1.m_Cents;} friend ostream& operator<<(ostream &out, Cents &c1); //Overloading << operator friend int operator+(const Cents &c1, const Cents &c2); //Overloading
  • 一般开始,加上考虑本地 using 声明的 decltype(Beginning generically, plus decltype considering local using-declaration)
    问题 C++0x 的 ranged-for 循环有一个特殊的例外来处理数组(FDIS §6.5.4),并且有两个函数 std::begin 和 end,它们被重载以处理数组或选择开始/结束方法。 这让我相信可以编写一个接受泛型序列的函数来匹配 ranged-for 循环的行为: template<class C> void f(C &c) { using std::begin; using std::end; do_something_with(begin(c), end(c)); } 如果在 C 的命名空间中有“更具体”的开始/结束,它将通过 ADL 选择,否则代码“默认”为 std::begin/end。 然而,ranged-for 有一个特殊的例外是有原因的。 如果在命名空间中传递一个类型的数组,该数组的语义不同,begin/end 接受一个指针,则不会选择 std::begin/end 的数组形式: namespace ns { struct A {}; void begin(A*); // Does something completely different from std::begin. } void f_A() { // Imagine above f() called with an array of ns::A objects. ns::A c[42]
  • C++ operator重载运算符详解
    [toc] Chapter XIV C++ operator 重载运算符的作用: 主要是代替成员函数的方式为自建类型完成基本任务 当然, 用成员函数完全可以代替operator的功能, 但是使用起来绝对没有operator方便 operator 重载运算符方式: 既然是用于自建类型的运算, 则其可以有两种定义方式: 作为自建类型的成员函数, 定义在类的内部 此时operator的参数数目比具体重载的运算符操作数数目少一, 因为此时使用的一个隐含参数为* this, 并将其作为左操作数(第一个操作数) 如果需要将* this作为右操作数, 只能将operator作为友元函数 作为自建类型的友元函数, 定义在类的内部或外部 此时operator的参数数目与具体重载的运算符操作数数目相同 对于两种方式的选择, 需根据具体的需求而定, 但有以下几点准则可以提供参考: 有些运算符必须作为类成员被重载(下头具体说明)复合赋值运算符(+=, -=, *=, /=, %=等), 通常来说应该作为类成员, 但C++标准没有强制改变对象状态的运算符, 与给定类型密切相关的运算符(如++递增,–递减, *解引用), 通常作为类成员具有对称性的运算符(即左右操作数互换后不影响重载运算符内部操作的, 如算数运算符, 关系运算符等)通常作为普通函数或友元函数 operator运算符重载限制: 说白了
  • 相等运算符重载:是 (x!=y) == (!(x==y)) 吗?(Equality operator overloads: Is (x!=y) == (!(x==y))?)
    问题 C++ 标准是否保证(x!=y)始终与!(x==y)具有相同的真值? 我知道这里涉及许多微妙之处:运算符==和!=可能会被重载。 它们可能被重载以具有不同的返回类型(只需隐式转换为bool )。 甚至! -operator 可能在返回类型上重载。 这就是为什么我在上面随意提到“真值”,但试图进一步阐述它,利用隐式转换为bool ,并试图消除可能的歧义: bool ne = (x!=y); bool e = (x==y); bool result = (ne == (!e)); result在这里保证是true吗? C++ 标准在 5.10 节中指定了相等运算符,但似乎主要是在语法上定义它们(以及一些关于指针比较的语义)。 存在 EqualityComparable 的概念,但没有专门声明其运算符==与!=运算符的关系。 有来自 C++ 工作组的相关文档,说... 重要的是,相等/不等 [...] 表现为彼此的布尔否定。 毕竟,如果 operator==() 和 operator!=() 都返回 false,那么这个世界将毫无意义! 因此,在彼此方面实现这些运算符是很常见的 但是,这仅反映了 Common Sense™,并没有指定它们必须像这样实现。 一些背景:我只是想编写一个函数来检查两个值(未知类型)是否相等,如果不是,则打印一条错误消息。
  • 运算符重载和不同类型(Operator overloading and different types)
    问题 我有一个类 Score,它将在与整数的比较中大量使用。 我打算按照下面的代码重载 == 运算符以启用这些比较? public class Score { public Score(int score) { Value = score; } public static bool operator ==(Score x, int y) { return x != null && x.Value == y; } public static bool operator ==(int y, Score x) { return x != null && x.Value == y; } } 这是对运算符重载的明智使用吗? 我是否应该为运算符的 LH 和 RH 侧提供重载以允许使用对称? 回答1 我可能会继续定义从int到Score的隐式转换,这样当您处理相等时,您只需要处理单个类型。 public static implicit operator Score(int value) { return new Score { Value = value }; // or new Score(value); } // define bool operator ==(Score score1, Score score2) // elsewhere Score score = new Score {
  • SSE,内在函数和对齐方式(SSE, intrinsics, and alignment)
    问题 我已经使用许多SSE编译器内部函数编写了3D矢量类。 一切工作正常,直到我开始实例化具有3D向量作为new成员的类。 我在发布模式下遇到了奇怪的崩溃,但在调试模式下却没有,反之亦然。 因此,我阅读了一些文章,并认为我还需要将拥有3D向量类实例的类的类也对齐为16个字节。 所以我只是在类的前面添加了_MM_ALIGN16 ( _MM_ALIGN16 ( __declspec(align(16) )),如下所示: _MM_ALIGN16 struct Sphere { // .... Vector3 point; float radius }; 起初似乎解决了这个问题。 但是在更改了一些代码之后,我的程序再次开始以奇怪的方式崩溃。 我在网上搜索了更多内容,然后找到了一篇博客文章。 我尝试了作者恩斯特·霍特(Ernst Hot)所做的事情来解决该问题,它也对我有用。 我在类中添加了new和delete运算符,如下所示: _MM_ALIGN16 struct Sphere { // .... void *operator new (unsigned int size) { return _mm_malloc(size, 16); } void operator delete (void *p) { _mm_free(p); } Vector3 point; float radius
  • 您如何在javascript中重载[]运算符(How would you overload the [] operator in javascript)
    问题 我似乎找不到在javascript中重载[]运算符的方法。 外面有人知道吗? 我在想... MyClass.operator.lookup(index) { return myArray[index]; } 还是我没有看正确的东西。 回答1 您不能在JavaScript中重载运算符。 它是针对ECMAScript 4提出的,但被拒绝了。 我认为您不会很快看到它。 回答2 您可以使用ES6代理(在所有现代浏览器中都可用)进行此操作 var handler = { get: function(target, name) { return "Hello, " + name; } }; var proxy = new Proxy({}, handler); console.log(proxy.world); // output: Hello, world 查看有关MDN的详细信息。 回答3 简单的答案是JavaScript允许通过方括号访问Object的子级。 因此,您可以定义您的班级: MyClass = function(){ // Set some defaults that belong to the class via dot syntax or array syntax. this.some_property = 'my value is a string'; this[
  • 通过引用重载多个函数对象(Overloading multiple function objects by reference)
    问题 在 C++17 中,实现一个overload(fs...)函数是微不足道的,给定任意数量的参数fs...满足 FunctionObject,返回一个新的函数对象,它的行为类似于fs...的重载。 例子: template <typename... Ts> struct overloader : Ts... { template <typename... TArgs> overloader(TArgs&&... xs) : Ts{forward<TArgs>(xs)}... { } using Ts::operator()...; }; template <typename... Ts> auto overload(Ts&&... xs) { return overloader<decay_t<Ts>...>{forward<Ts>(xs)...}; } int main() { auto o = overload([](char){ cout << "CHAR"; }, [](int) { cout << "INT"; }); o('a'); // prints "CHAR" o(0); // prints "INT" } 魔杖盒上的现场示例 由于上面的overloader继承自Ts... ,它需要复制或移动函数对象才能工作。 我想要一些提供相同重载行为的东西
  • 在 C++ 中一般比较继承层次结构中的对象(Generically comparing objects in an inheritance hierarchy in c++)
    问题 我打算写一个这样的多图 std::multimap <key, base_ptr> mymap; 我希望能够存储从基派生的许多派生类(比如Der1 、 Der2 )的指针。 现在,当我尝试将一个对象插入到地图中时,我首先在键上进行查找,然后我需要比较该对象是否为 EQUIVALENT(不必是同一个对象,因此不进行指针比较)到一个在那个位置。 因此,为此可以说我覆盖== operator或编写某种比较函数。 现在我想以这样的方式编写代码,以便在添加新的派生类时,我不必更改或添加任何内容。 所以我认为必须有一种通用的方式来写这个。 却一时想不起来。 我在想类似以下的事情 class Base { virtual Base * get() { return this; } virtual bool isEqual(const Base& toObj) { .... } } class Der1 { Der1 * get() { return this; } bool isEqual(const Der1& toObj) { .... } } 但这似乎也不起作用。 因为当我这样做时: Base* bp1; Base* bp2; bp1->get()->isEqual(*(bp2->get())) 我看到,调用get()并最终在get()派生类的如我所料
  • 将空指针传递给新的展示位置(Passing null pointer to placement new)
    问题 默认位置new运算符在18.6 [support.dynamic]¶1中声明为非抛出异常规范: void* operator new (std::size_t size, void* ptr) noexcept; 除了return ptr;之外,该函数不执行任何操作return ptr; 因此将它设为noexcept是合理的,但是根据5.3.4 [expr.new]¶15,这意味着编译器必须在调用对象的构造函数之前检查它是否不返回null: -15- [注意:除非用非抛出异常规范(15.4)声明分配函数,否则它会抛出std::bad_alloc异常来指示分配存储失败(第15条,18.6.2.1); 否则返回非空指针。 如果使用非抛出异常规范声明分配函数,则它返回null表示分配存储失败,否则返回non-null指针。 —尾注]如果分配函数返回null,则不应完成初始化,不得调用释放函数,并且new-expression的值应为null。 在我看来(专门用于new放置,而不是一般而言),此null检查是一个不幸的性能损失,尽管很小。 我一直在调试一些代码,这些代码在性能非常敏感的代码路径中使用了placement new来改善编译器的代码生成,并且在程序集中观察到null的检查。 通过提供特定于类的放置new重载,该重载使用引发异常的规范声明(即使它不可能引发)
  • C ++中的重载赋值运算符(Overloading assignment operator in C++)
    问题 据我了解,当重载operator =时,返回值应为非const引用。 A& A::operator=( const A& ) { // check for self-assignment, do assignment return *this; } 在以下情况下,允许调用非常量成员函数是非常量的: ( a = b ).f(); 但是为什么要返回参考? 如果未将返回值声明为引用(假设按值返回),在什么情况下会出现问题? 假定复制构造函数已正确实现。 回答1 不返回引用会浪费资源,并且会产生怪异的设计。 为什么要为操作员的所有用户制作一份副本,即使几乎所有用户都将放弃该值? a = b; // huh, why does this create an unnecessary copy? 另外,对于您的班级用户来说,这是令人惊讶的,因为内置的赋值运算符不会同样进行复制 int &a = (some_int = 0); // works 回答2 重载运算符时的一个很好的一般建议是“按原语类型做”,而赋值给原语类型的默认行为是这样做。 如果您认为需要,可以不选择不返回任何内容来禁用其他表达式中的赋值,但是返回一个副本根本没有意义:如果调用者想要创建一个副本,则可以在引用之外进行复制,如果他们愿意不需要副本,不需要生成不需要的临时文件。 回答3 因为f()可以修改a 。
  • [引擎开发] 深入C++内存管理
    引入 说到C++的内存管理,我们可能会想到栈空间的本地变量、堆上通过new动态分配的变量以及全局命名空间的变量等,这些变量的分配位置都是由系统来控制管理的,而调用者只需要考虑变量的生命周期相关内容即可,而无需关心变量的具体布局。这对于普通软件的开发已经足够,但对于引擎开发而言,我们必须对内存有着更为精细的管理。 [本文的大纲] 基础概念 内存布局 函数栈 全局变量 内存对齐 内存碎片 继承类布局 字节序 POD类型 操作系统 SIMD 高速缓存 虚拟内存 置换算法 C++语法 位域 new和placement new alignas和alignof allocator shared_ptr, unique_ptr和weak_ptr 分配和管理机制 带freelist的分配器 buddy分配器 含对齐的分配器 单帧分配器模型 双帧分配器模型 堆栈分配器模型 双端堆栈分配器模型 池分配器模型 tcmalloc的内存分配 碎片整理机制 容器的访问局部性 ue4内存管理 自定义内存管理 FMallocBinned Allocator 动态内存管理 垃圾回收 基础概念 在文章的开篇,先对一些基础概念进行简单的介绍,以便能够更好地理解后续的内容。 内存布局 内存分布(可执行映像) 如图,描述了C++程序的内存分布。 Code Segment(代码区) 也称Text Segment
  • 为什么不允许对存储在STL容器中的类重载operator&()?(Why is overloading operator&() prohibited for classes stored in STL containers?)
    问题 在本文中突然出现(问题2),我看到一条声明,如果该类具有重载的operator&() ,则C ++ Standard禁止使用STL容器存储该类的元素。 重载operator&()的确确实是个问题,但是看起来像默认的“ address-of”运算符可以通过在boost :: addressof()中使用的一组看起来很脏的强制转换很容易地使用,并且被认为是可移植的,并且标准编译器。 为什么在存在boost::addressof()解决方法的情况下,对于存储在STL容器中的类,为什么不允许重载的operator&() ? 回答1 在没有查看链接的情况下,我认为boost::addressof()中的技巧是在不超载一元前缀&将对象保存在std lib容器中的要求之后发明的。 我隐约记得Pete Becker(当时在Dinkumware的标准库实现中工作)曾经说过,凡是重载address-of运算符并希望其标准库实现仍能正常工作的人都应受到必须执行此操作的标准库的惩罚。 回答2 可能是因为,比起创建std :: addressof()函数并用它替换容器代码中的&每次使用,仅禁止使用重载的operator&()类要麻烦得多。 回答3 该标准于1998年最终确定,并于2003年修复,而boost::addressof日期可追溯到2002年初。 此外,还不清楚addressof是否是答案。
  • Java为什么不需要运算符重载? [关闭](Why doesn't Java need Operator Overloading? [closed])
    问题 关门了。 这个问题是基于意见的。 它当前不接受答案。 想要改善这个问题吗? 更新问题,以便可以通过编辑此帖子以事实和引用的形式回答。 4年前关闭。 改善这个问题 Java为什么不需要运算符重载? Java有什么方法可以支持它吗? 回答1 Java仅允许对基本数字类型进行算术运算。 这是喜忧参半的事情,因为尽管在其他类型(如复数,向量等)上定义运算符很方便,但始终存在与实现相关的特性。 因此,运营商并不总是按照您的期望去做。 通过避免运算符重载,可以更清楚地知道何时调用哪个函数。 明智的设计在某些人的眼中动了。 回答2 Java不需要“运算符”重载,因为没有语言需要它。 a + b只是a.Add(b) “语法糖”(实际上,有人认为a.Add(b)只是Add(a,b)语法糖) 回答3 这个相关的问题可能会有所帮助。 简而言之,由于C ++中的重载问题,在设计Java时有意避免了运算符重载。 Scala是一种较新的JVM语言,其语法允许方法重载,其功能非常类似于运算符重载,而没有C ++运算符重载的限制。 例如,在Scala中,可以定义一个名为+的方法。 也可以省略. 方法调用中的运算符和括号: case class A(value: Int) { def +(other: A) = new A(value + other.value) } scala> new A(1) +
  • 重载和重写方法中的多态性(Polymorphism in Overloaded and Overridden Methods)
    问题 让我们以这个简单的 Java 代码为例: public class Animal { public void eat() { System.out.println("Generic Animal Eating Generically"); } } public class Horse extends Animal { public void eat() { System.out.println("Horse eating hay "); } public void eat(String s) { System.out.println("Horse eating " + s); } } 我试图弄清楚将运行三个eat() 方法中的哪个版本。 现在,当我输入 Animal a = new Animal(); a.eat(); 输出是“Generic Animal Eating Generically”,完全可以理解。 当我输入时会发生同样的事情: Horse h = new Horse(); h.eat(); 输出是“马吃干草”,这也是完全合乎逻辑的。 不过,这就是让我感到困惑的地方。 当我输入: Animal ah = new Horse(); ah.eat(); 我得到: Horse eating hay 我希望编译器从 Animal 类引用而不是 Horse
  • 如何合理地使新的展示位置运算符超载?(How could I sensibly overload placement operator new?)
    问题 C ++允许重载operator new -全局和每个类-通常operator new , operator new[]与用于new[]语句和放置operator new分开。 这三个中的前两个通常会因使用自定义分配器和添加跟踪而超载。 但是operator new放置operator new看起来非常简单-实际上它什么也没做。 例如,在Visual C ++中,默认实现只是返回传递给调用的地址: //from new.h inline void* operator new( size_t, void* where ) { return where; } 它还能做什么? 为什么以及如何合理地使operator new放置operator new超载? 回答1 正确的答案是您不能替换new的运算符位置。 §18.4.1.3安置表格这些函数是保留的,C ++程序可能未定义替换标准C ++库中版本的函数。 基本原理:分配和释放运算符的唯一目的是分配和取消分配内存,因此,在给定内存的情况下,不应再执行其他操作。 (标准特别指出这些功能“有意不执行其他操作”。) 回答2 从技术上讲, operator new放置operator new是除需要的内存大小外还需要其他参数的任何operator new 。 因此, new(std::nothrow) X使用operator
  • 为什么不能将重载运算符定义为类的静态成员?(Why overloaded operators cannot be defined as static members of a class?)
    问题 C ++语法允许在struct / class内部定义重载运算符,例如: struct X { void operator+(X); } 或在struct / class之外,例如: void operator+(X, X); 但不像 struct X { static void operator+(X, X); } 是否有人知道做出此决定的原因? 为什么不允许使用第三种形式? (MSVC给出语法错误)。 也许背后有一些故事吗? ps同时存在第一和第二个定义会产生歧义: 1>CppTest1.cxx 1>c:\ballerup\misc\cf_html\cpptest1.cxx(39) : error C2593: 'operator +' is ambiguous 1> c:\ballerup\misc\cf_html\cpptest1.cxx(13): could be 'void B1::operator +(B1 &)' 1> c:\ballerup\misc\cf_html\cpptest1.cxx(16): or 'void operator +(B1 &,B1 &)' 1> while trying to match the argument list '(B1, B1)' 我不明白为什么这种歧义比在1,3或2,3之间更好。 回答1 我对此概念的任何C +
  • 为什么不能使用非成员函数来重载赋值运算符?(Why cannot a non-member function be used for overloading the assignment operator?)
    问题 可以使用成员函数而不是非成员friend函数来重载赋值运算符: class Test { int a; public: Test(int x) :a(x) {} friend Test& operator=(Test &obj1, Test &obj2); }; Test& operator=(Test &obj1, Test &obj2)//Not implemented fully. just for test. { return obj1; } 它导致此错误: 错误C2801:“ operator =”必须是非静态成员 为什么不能使用friend函数来重载赋值运算符? 编译器允许使用friend重载其他运算符,例如+=和-= 。 支持operator=的固有问题/局限性是什么? 回答1 因为编译器提供的默认operator= (成员副本一)始终优先。 即,您的朋友operator=永远不会被调用。 编辑:这个答案正在回答 支持=运算符的固有问题/局限性是什么? 问题的一部分。 这里的其他答案引用了标准中您不能做到的部分,但这很可能就是标准那部分是用这种方式编写的。 回答2 首先,应该注意的是,这与将操作员具体实现为朋友无关。 实际上,这是将复制分配实现为成员函数或非成员(独立)函数。 该独立函数是否会成为朋友完全无关紧要:可能会,也可能不会,这取决于要在类内部访问的内容